diff --git a/docker/Dockerfile-dim-migrations b/docker/Dockerfile-dim-migrations index 0e5ec7e..a543764 100644 --- a/docker/Dockerfile-dim-migrations +++ b/docker/Dockerfile-dim-migrations @@ -23,7 +23,6 @@ ARG TARGETARCH WORKDIR / COPY LICENSE / COPY /src/database /src/database -COPY /src/processes/Processes.Worker.Library /src/processes/Processes.Worker.Library WORKDIR /src/database/Dim.Migrations RUN dotnet publish "Dim.Migrations.csproj" -c Release -o /migrations/publish diff --git a/src/Dim.sln b/src/Dim.sln index f52c3a4..cb42844 100644 --- a/src/Dim.sln +++ b/src/Dim.sln @@ -6,12 +6,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "clients", "clients", "{B84A EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dim.Clients", "clients\Dim.Clients\Dim.Clients.csproj", "{8356C7AF-6F88-4A62-B3E9-5656634A6FEA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Processes.Library", "processes\Processes.Library\Processes.Library.csproj", "{BFDDFCF5-8F35-4348-A568-57D8E34DF289}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Processes.Worker", "processes\Processes.Worker\Processes.Worker.csproj", "{E5F65B6F-BD8F-4FAF-80A2-69C9DA20DCC2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Processes.Worker.Library", "processes\Processes.Worker.Library\Processes.Worker.Library.csproj", "{4F40B8F2-12D4-403B-B666-8F0540354455}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "database", "database", "{4A305F87-23B4-4929-B138-4B7D2710526F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dim.DbAccess", "database\Dim.DbAccess\Dim.DbAccess.csproj", "{6984539B-7B5A-481E-A955-3AE537D43166}" @@ -30,10 +26,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dim.Web", "web\Dim.Web\Dim. EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{CB1B7D43-9AFC-47EF-8915-A547F7F553AB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Processes.Library.Tests", "..\tests\processes\Processes.Library.Tests\Processes.Library.Tests.csproj", "{AA29EECC-CD77-4452-B48E-CC038E4FBB69}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Processes.Worker.Library.Tests", "..\tests\processes\Processes.Worker.Library.Tests\Processes.Worker.Library.Tests.csproj", "{9888C703-CC13-47EB-89F0-B8A34D64BD07}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Shared", "..\tests\shared\Tests.Shared\Tests.Shared.csproj", "{0D288AF0-1CE5-4B2B-9F80-532040F24BCF}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DimProcess.Executor.Tests", "..\tests\processes\DimProcess.Executor.Tests\DimProcess.Executor.Tests.csproj", "{A44447B0-794D-451A-A571-E3B761174B48}" @@ -56,18 +48,10 @@ Global {8356C7AF-6F88-4A62-B3E9-5656634A6FEA}.Debug|Any CPU.Build.0 = Debug|Any CPU {8356C7AF-6F88-4A62-B3E9-5656634A6FEA}.Release|Any CPU.ActiveCfg = Release|Any CPU {8356C7AF-6F88-4A62-B3E9-5656634A6FEA}.Release|Any CPU.Build.0 = Release|Any CPU - {BFDDFCF5-8F35-4348-A568-57D8E34DF289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BFDDFCF5-8F35-4348-A568-57D8E34DF289}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BFDDFCF5-8F35-4348-A568-57D8E34DF289}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BFDDFCF5-8F35-4348-A568-57D8E34DF289}.Release|Any CPU.Build.0 = Release|Any CPU {E5F65B6F-BD8F-4FAF-80A2-69C9DA20DCC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5F65B6F-BD8F-4FAF-80A2-69C9DA20DCC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5F65B6F-BD8F-4FAF-80A2-69C9DA20DCC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5F65B6F-BD8F-4FAF-80A2-69C9DA20DCC2}.Release|Any CPU.Build.0 = Release|Any CPU - {4F40B8F2-12D4-403B-B666-8F0540354455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F40B8F2-12D4-403B-B666-8F0540354455}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F40B8F2-12D4-403B-B666-8F0540354455}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F40B8F2-12D4-403B-B666-8F0540354455}.Release|Any CPU.Build.0 = Release|Any CPU {6984539B-7B5A-481E-A955-3AE537D43166}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6984539B-7B5A-481E-A955-3AE537D43166}.Debug|Any CPU.Build.0 = Debug|Any CPU {6984539B-7B5A-481E-A955-3AE537D43166}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -92,14 +76,6 @@ Global {1B50DC13-DB8A-41CF-9D40-A8740B068AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {1B50DC13-DB8A-41CF-9D40-A8740B068AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {1B50DC13-DB8A-41CF-9D40-A8740B068AC2}.Release|Any CPU.Build.0 = Release|Any CPU - {AA29EECC-CD77-4452-B48E-CC038E4FBB69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AA29EECC-CD77-4452-B48E-CC038E4FBB69}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AA29EECC-CD77-4452-B48E-CC038E4FBB69}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AA29EECC-CD77-4452-B48E-CC038E4FBB69}.Release|Any CPU.Build.0 = Release|Any CPU - {9888C703-CC13-47EB-89F0-B8A34D64BD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9888C703-CC13-47EB-89F0-B8A34D64BD07}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9888C703-CC13-47EB-89F0-B8A34D64BD07}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9888C703-CC13-47EB-89F0-B8A34D64BD07}.Release|Any CPU.Build.0 = Release|Any CPU {0D288AF0-1CE5-4B2B-9F80-532040F24BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0D288AF0-1CE5-4B2B-9F80-532040F24BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D288AF0-1CE5-4B2B-9F80-532040F24BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -127,17 +103,13 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {8356C7AF-6F88-4A62-B3E9-5656634A6FEA} = {B84A3CAB-AC86-4B2D-A490-79E1002350FF} - {BFDDFCF5-8F35-4348-A568-57D8E34DF289} = {30AA679F-7CF6-4FBE-9A13-BEF98BCFE3D2} {E5F65B6F-BD8F-4FAF-80A2-69C9DA20DCC2} = {30AA679F-7CF6-4FBE-9A13-BEF98BCFE3D2} - {4F40B8F2-12D4-403B-B666-8F0540354455} = {30AA679F-7CF6-4FBE-9A13-BEF98BCFE3D2} {6984539B-7B5A-481E-A955-3AE537D43166} = {4A305F87-23B4-4929-B138-4B7D2710526F} {0A85DB84-41A0-4EE0-815B-D922329A8BCA} = {4A305F87-23B4-4929-B138-4B7D2710526F} {41AA384E-E433-440E-A02E-83F03AC98A63} = {30AA679F-7CF6-4FBE-9A13-BEF98BCFE3D2} {F14C5E02-DC54-4A27-B2DE-513A644E6473} = {30AA679F-7CF6-4FBE-9A13-BEF98BCFE3D2} {1621A06B-9AF2-421C-BB48-08028560E108} = {4A305F87-23B4-4929-B138-4B7D2710526F} {1B50DC13-DB8A-41CF-9D40-A8740B068AC2} = {D20B95EF-D7D9-45BA-B5A4-C8D3B64AC745} - {AA29EECC-CD77-4452-B48E-CC038E4FBB69} = {CB1B7D43-9AFC-47EF-8915-A547F7F553AB} - {9888C703-CC13-47EB-89F0-B8A34D64BD07} = {CB1B7D43-9AFC-47EF-8915-A547F7F553AB} {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} diff --git a/src/clients/Dim.Clients/Dim.Clients.csproj b/src/clients/Dim.Clients/Dim.Clients.csproj index 7897523..83ece78 100644 --- a/src/clients/Dim.Clients/Dim.Clients.csproj +++ b/src/clients/Dim.Clients/Dim.Clients.csproj @@ -36,9 +36,9 @@ - - - + + + diff --git a/src/database/Dim.DbAccess/Dim.DbAccess.csproj b/src/database/Dim.DbAccess/Dim.DbAccess.csproj index fdb9fcb..c58a42b 100644 --- a/src/database/Dim.DbAccess/Dim.DbAccess.csproj +++ b/src/database/Dim.DbAccess/Dim.DbAccess.csproj @@ -30,8 +30,8 @@ - - + + diff --git a/src/database/Dim.DbAccess/DimProcessDbContextAccess.cs b/src/database/Dim.DbAccess/DimProcessDbContextAccess.cs new file mode 100644 index 0000000..dab8978 --- /dev/null +++ b/src/database/Dim.DbAccess/DimProcessDbContextAccess.cs @@ -0,0 +1,40 @@ +/******************************************************************************** + * Copyright (c) 2025 BMW Group AG + * Copyright 2025 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.Entities; +using Dim.Entities.Entities; +using Dim.Entities.Enums; +using Microsoft.EntityFrameworkCore; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; + +namespace Dim.DbAccess; + +public class DimProcessDbContextAccess(DimDbContext dbContext) : + IProcessRepositoryContextAccess, ProcessStep, ProcessStepType, ProcessTypeId, ProcessStepTypeId> +{ + public DbSet Processes => dbContext.Processes; + public DbSet> ProcessSteps => dbContext.ProcessSteps; + public DbSet> ProcessStepStatuses => dbContext.ProcessStepStatuses; + + public Process CreateProcess(Guid id, ProcessTypeId processTypeId, Guid version) => new(id, processTypeId, version); + public ProcessStep CreateProcessStep(Guid id, ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid processId, DateTimeOffset now) => new(id, processStepTypeId, processStepStatusId, processId, now); +} diff --git a/src/database/Dim.DbAccess/DimRepositories.cs b/src/database/Dim.DbAccess/DimRepositories.cs index 370cbf9..e8ba9cf 100644 --- a/src/database/Dim.DbAccess/DimRepositories.cs +++ b/src/database/Dim.DbAccess/DimRepositories.cs @@ -20,53 +20,25 @@ using Dim.DbAccess.Repositories; using Dim.Entities; -using Microsoft.EntityFrameworkCore; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Dim.Entities.Entities; +using Dim.Entities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.DBAccess; using System.Collections.Immutable; namespace Dim.DbAccess; -public class DimRepositories(DimDbContext dbContext) - : IDimRepositories +public class DimRepositories(DimDbContext dbContext) : + AbstractRepositories(dbContext), + IDimRepositories { - private static readonly IReadOnlyDictionary> Types = new Dictionary> { - { typeof(IProcessStepRepository), context => new ProcessStepRepository(context) }, - { typeof(ITenantRepository), context => new TenantRepository(context) }, - { typeof(ITechnicalUserRepository), context => new TechnicalUserRepository(context) } - }.ToImmutableDictionary(); - - public RepositoryType GetInstance() - { - object? repository = default; - - if (Types.TryGetValue(typeof(RepositoryType), out var createFunc)) - { - repository = createFunc(dbContext); - } - - return (RepositoryType)(repository ?? throw new ArgumentException($"unexpected type {typeof(RepositoryType).Name}", nameof(RepositoryType))); - } - - /// - public TEntity Attach(TEntity entity, Action? setOptionalParameters = null) where TEntity : class - { - var attachedEntity = dbContext.Attach(entity).Entity; - setOptionalParameters?.Invoke(attachedEntity); - - return attachedEntity; - } - - public Task SaveAsync() - { - try - { - return dbContext.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException e) - { - throw new ConflictException("while processing a concurrent update was saved to the database (reason could also be data to be deleted is no longer existing)", e); - } - } - - public void Clear() => dbContext.ChangeTracker.Clear(); + protected override IReadOnlyDictionary> RepositoryTypes => Types; + + private static readonly IReadOnlyDictionary> Types = ImmutableDictionary.CreateRange( + [ + CreateTypeEntry(context => new TenantRepository(context)), + CreateTypeEntry(context => new TechnicalUserRepository(context)), + CreateTypeEntry>(context => new ProcessStepRepository, ProcessStep, ProcessStepType, ProcessTypeId, ProcessStepTypeId>(new DimProcessDbContextAccess(context))), + ]); } diff --git a/src/database/Dim.DbAccess/IDimRepositories.cs b/src/database/Dim.DbAccess/IDimRepositories.cs index 1670e59..4785868 100644 --- a/src/database/Dim.DbAccess/IDimRepositories.cs +++ b/src/database/Dim.DbAccess/IDimRepositories.cs @@ -18,12 +18,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; + namespace Dim.DbAccess; -public interface IDimRepositories -{ - RepositoryType GetInstance(); - TEntity Attach(TEntity entity, Action? setOptionalParameters = null) where TEntity : class; - Task SaveAsync(); - void Clear(); -} +public interface IDimRepositories : IRepositories; diff --git a/src/database/Dim.DbAccess/Models/ProcessData.cs b/src/database/Dim.DbAccess/Models/ProcessData.cs index 2656d8e..76e29f9 100644 --- a/src/database/Dim.DbAccess/Models/ProcessData.cs +++ b/src/database/Dim.DbAccess/Models/ProcessData.cs @@ -19,6 +19,7 @@ ********************************************************************************/ using Dim.Entities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; namespace Dim.DbAccess.Models; diff --git a/src/database/Dim.DbAccess/Models/VerifyProcessData.cs b/src/database/Dim.DbAccess/Models/VerifyProcessData.cs deleted file mode 100644 index e07b2af..0000000 --- a/src/database/Dim.DbAccess/Models/VerifyProcessData.cs +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************** - * 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.Entities.Entities; - -namespace Dim.DbAccess.Models; - -public record VerifyProcessData( - Process? Process, - IEnumerable? ProcessSteps -); diff --git a/src/database/Dim.DbAccess/Repositories/IProcessStepRepository.cs b/src/database/Dim.DbAccess/Repositories/IProcessStepRepository.cs deleted file mode 100644 index e225f61..0000000 --- a/src/database/Dim.DbAccess/Repositories/IProcessStepRepository.cs +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************** - * 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.DbAccess.Models; -using Dim.Entities.Entities; -using Dim.Entities.Enums; - -namespace Dim.DbAccess.Repositories; - -/// -/// Repository for accessing and creating processSteps on persistence layer. -/// -public interface IProcessStepRepository -{ - Process CreateProcess(ProcessTypeId processTypeId); - ProcessStep CreateProcessStep(ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid processId); - IEnumerable CreateProcessStepRange(IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus); - void AttachAndModifyProcessStep(Guid processStepId, Action? initialize, Action modify); - void AttachAndModifyProcessSteps(IEnumerable<(Guid ProcessStepId, Action? Initialize, Action Modify)> processStepIdsInitializeModifyData); - IAsyncEnumerable GetActiveProcesses(IEnumerable processTypeIds, IEnumerable processStepTypeIds, DateTimeOffset lockExpiryDate); - IAsyncEnumerable<(Guid ProcessStepId, ProcessStepTypeId ProcessStepTypeId)> GetProcessStepData(Guid processId); - Task<(bool ProcessExists, VerifyProcessData ProcessData)> IsValidProcess(Guid processId, ProcessTypeId processTypeId, IEnumerable processSetpTypeIds); -} diff --git a/src/database/Dim.DbAccess/Repositories/ProcessStepRepository.cs b/src/database/Dim.DbAccess/Repositories/ProcessStepRepository.cs deleted file mode 100644 index 3e7d703..0000000 --- a/src/database/Dim.DbAccess/Repositories/ProcessStepRepository.cs +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************** - * 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.DbAccess.Models; -using Dim.Entities; -using Dim.Entities.Entities; -using Dim.Entities.Enums; -using Microsoft.EntityFrameworkCore; -using ProcessTypeId = Dim.Entities.Enums.ProcessTypeId; - -namespace Dim.DbAccess.Repositories; - -public class ProcessStepRepository(DimDbContext dbContext) - : IProcessStepRepository -{ - public Process CreateProcess(ProcessTypeId processTypeId) => - dbContext.Add(new Process(Guid.NewGuid(), processTypeId, Guid.NewGuid())).Entity; - - public ProcessStep CreateProcessStep(ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid processId) => - dbContext.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, processId, DateTimeOffset.UtcNow)).Entity; - - public IEnumerable CreateProcessStepRange(IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) - { - var processSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToList(); - dbContext.AddRange(processSteps); - return processSteps; - } - - public void AttachAndModifyProcessStep(Guid processStepId, Action? initialize, Action modify) - { - var step = new ProcessStep(processStepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - dbContext.Attach(step); - step.DateLastChanged = DateTimeOffset.UtcNow; - modify(step); - } - - public void AttachAndModifyProcessSteps(IEnumerable<(Guid ProcessStepId, Action? Initialize, Action Modify)> processStepIdsInitializeModifyData) - { - var stepModifyData = processStepIdsInitializeModifyData.Select(data => - { - var step = new ProcessStep(data.ProcessStepId, default, default, Guid.Empty, default); - data.Initialize?.Invoke(step); - return (Step: step, data.Modify); - }).ToList(); - dbContext.AttachRange(stepModifyData.Select(data => data.Step)); - stepModifyData.ForEach(data => - { - data.Step.DateLastChanged = DateTimeOffset.UtcNow; - data.Modify(data.Step); - }); - } - - public IAsyncEnumerable GetActiveProcesses(IEnumerable processTypeIds, IEnumerable processStepTypeIds, DateTimeOffset lockExpiryDate) => - dbContext.Processes - .AsNoTracking() - .Where(process => - processTypeIds.Contains(process.ProcessTypeId) && - process.ProcessSteps.Any(step => processStepTypeIds.Contains(step.ProcessStepTypeId) && step.ProcessStepStatusId == ProcessStepStatusId.TODO) && - (process.LockExpiryDate == null || process.LockExpiryDate < lockExpiryDate)) - .AsAsyncEnumerable(); - - public IAsyncEnumerable<(Guid ProcessStepId, ProcessStepTypeId ProcessStepTypeId)> GetProcessStepData(Guid processId) => - dbContext.ProcessSteps - .AsNoTracking() - .Where(step => - step.ProcessId == processId && - step.ProcessStepStatusId == ProcessStepStatusId.TODO) - .OrderBy(step => step.ProcessStepTypeId) - .Select(step => - new ValueTuple( - step.Id, - step.ProcessStepTypeId)) - .AsAsyncEnumerable(); - - public Task<(bool ProcessExists, VerifyProcessData ProcessData)> IsValidProcess(Guid processId, ProcessTypeId processTypeId, IEnumerable processStepTypeIds) => - dbContext.Processes - .AsNoTracking() - .Where(x => x.Id == processId && x.ProcessTypeId == processTypeId) - .Select(x => new ValueTuple( - true, - new VerifyProcessData( - x, - x.ProcessSteps - .Where(step => - processStepTypeIds.Contains(step.ProcessStepTypeId) && - step.ProcessStepStatusId == ProcessStepStatusId.TODO)) - )) - .SingleOrDefaultAsync(); -} diff --git a/src/database/Dim.Entities/Dim.Entities.csproj b/src/database/Dim.Entities/Dim.Entities.csproj index dfbf9a3..805633a 100644 --- a/src/database/Dim.Entities/Dim.Entities.csproj +++ b/src/database/Dim.Entities/Dim.Entities.csproj @@ -34,6 +34,7 @@ all - + + diff --git a/src/database/Dim.Entities/DimDbContext.cs b/src/database/Dim.Entities/DimDbContext.cs index 61df8bb..7d2cd36 100644 --- a/src/database/Dim.Entities/DimDbContext.cs +++ b/src/database/Dim.Entities/DimDbContext.cs @@ -21,25 +21,13 @@ using Dim.Entities.Entities; using Dim.Entities.Enums; using Microsoft.EntityFrameworkCore; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Context; namespace Dim.Entities; -public class DimDbContext : DbContext +public class DimDbContext(DbContextOptions options) : + ProcessDbContext(options) { - protected DimDbContext() - { - } - - public DimDbContext(DbContextOptions options) - : base(options) - { - } - - public virtual DbSet Processes { get; set; } = default!; - public virtual DbSet ProcessSteps { get; set; } = default!; - public virtual DbSet ProcessStepStatuses { get; set; } = default!; - public virtual DbSet ProcessStepTypes { get; set; } = default!; - public virtual DbSet ProcessTypes { get; set; } = default!; public virtual DbSet Tenants { get; set; } = default!; public virtual DbSet TechnicalUsers { get; set; } = default!; @@ -53,38 +41,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.HasAnnotation("Relational:Collation", "en_US.utf8"); modelBuilder.HasDefaultSchema("dim"); - modelBuilder.Entity() - .HasOne(d => d.ProcessType) - .WithMany(p => p.Processes) - .HasForeignKey(d => d.ProcessTypeId) - .OnDelete(DeleteBehavior.ClientSetNull); - - modelBuilder.Entity() - .HasOne(d => d.Process) - .WithMany(p => p.ProcessSteps) - .HasForeignKey(d => d.ProcessId) - .OnDelete(DeleteBehavior.ClientSetNull); - - modelBuilder.Entity() - .HasData( - Enum.GetValues(typeof(ProcessTypeId)) - .Cast() - .Select(e => new ProcessType(e)) - ); - - modelBuilder.Entity() - .HasData( - Enum.GetValues(typeof(ProcessStepStatusId)) - .Cast() - .Select(e => new ProcessStepStatus(e)) - ); - - modelBuilder.Entity() - .HasData( - Enum.GetValues(typeof(ProcessStepTypeId)) - .Cast() - .Select(e => new ProcessStepType(e)) - ); + base.OnModelCreating(modelBuilder); modelBuilder.Entity(t => { diff --git a/src/database/Dim.Entities/Entities/Process.cs b/src/database/Dim.Entities/Entities/Process.cs index 048c4f3..b3dbf2f 100644 --- a/src/database/Dim.Entities/Entities/Process.cs +++ b/src/database/Dim.Entities/Entities/Process.cs @@ -20,38 +20,13 @@ using Dim.Entities.Enums; using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities; using System.ComponentModel.DataAnnotations; namespace Dim.Entities.Entities; -public class Process : ILockableEntity +public class Process(Guid id, ProcessTypeId processTypeId, Guid version) : AbstractProcess(id, processTypeId, version) { - private Process() - { - ProcessSteps = new HashSet(); - Tenants = new HashSet(); - TechnicalUsers = new HashSet(); - } - - public Process(Guid id, ProcessTypeId processTypeId, Guid version) : this() - { - Id = id; - ProcessTypeId = processTypeId; - Version = version; - } - - public Guid Id { get; private set; } - - public ProcessTypeId ProcessTypeId { get; set; } - - public DateTimeOffset? LockExpiryDate { get; set; } - - [ConcurrencyCheck] - public Guid Version { get; set; } - - // Navigation properties - public virtual ProcessType? ProcessType { get; set; } - public virtual ICollection ProcessSteps { get; private set; } public virtual ICollection Tenants { get; private set; } public virtual ICollection TechnicalUsers { get; private set; } } diff --git a/src/database/Dim.Entities/Entities/ProcessStep.cs b/src/database/Dim.Entities/Entities/ProcessStep.cs deleted file mode 100644 index 513d5ad..0000000 --- a/src/database/Dim.Entities/Entities/ProcessStep.cs +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************** - * 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.Entities.Enums; - -namespace Dim.Entities.Entities; - -public class ProcessStep( - Guid id, - ProcessStepTypeId processStepTypeId, - ProcessStepStatusId processStepStatusId, - Guid processId, - DateTimeOffset dateCreated) -{ - public Guid Id { get; private set; } = id; - - public ProcessStepTypeId ProcessStepTypeId { get; private set; } = processStepTypeId; - - public ProcessStepStatusId ProcessStepStatusId { get; set; } = processStepStatusId; - - public Guid ProcessId { get; private set; } = processId; - - public DateTimeOffset DateCreated { get; private set; } = dateCreated; - - public DateTimeOffset? DateLastChanged { get; set; } - - public string? Message { get; set; } - - // Navigation properties - public virtual ProcessStepType? ProcessStepType { get; private set; } - public virtual ProcessStepStatus? ProcessStepStatus { get; set; } - public virtual Process? Process { get; private set; } -} diff --git a/src/database/Dim.Entities/Entities/ProcessStepStatus.cs b/src/database/Dim.Entities/Entities/ProcessStepStatus.cs deleted file mode 100644 index ef7619e..0000000 --- a/src/database/Dim.Entities/Entities/ProcessStepStatus.cs +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************** - * 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.Entities.Enums; -using System.ComponentModel.DataAnnotations; - -namespace Dim.Entities.Entities; - -public class ProcessStepStatus -{ - private ProcessStepStatus() - { - this.Label = null!; - this.ProcessSteps = new HashSet(); - } - - public ProcessStepStatus(ProcessStepStatusId processStepStatusId) : this() - { - Id = processStepStatusId; - Label = processStepStatusId.ToString(); - } - - public ProcessStepStatusId Id { get; private set; } - - [MaxLength(255)] - public string Label { get; private set; } - - // Navigation properties - public virtual ICollection ProcessSteps { get; private set; } -} diff --git a/src/database/Dim.Entities/Entities/ProcessStepType.cs b/src/database/Dim.Entities/Entities/ProcessStepType.cs deleted file mode 100644 index 87d1ccc..0000000 --- a/src/database/Dim.Entities/Entities/ProcessStepType.cs +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************** - * 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.Entities.Enums; -using System.ComponentModel.DataAnnotations; - -namespace Dim.Entities.Entities; - -public class ProcessStepType -{ - private ProcessStepType() - { - this.Label = null!; - this.ProcessSteps = new HashSet(); - } - - public ProcessStepType(ProcessStepTypeId processStepTypeId) : this() - { - Id = processStepTypeId; - Label = processStepTypeId.ToString(); - } - - public ProcessStepTypeId Id { get; private set; } - - [MaxLength(255)] - public string Label { get; private set; } - - // Navigation properties - public virtual ICollection ProcessSteps { get; private set; } -} diff --git a/src/database/Dim.Entities/Entities/ProcessType.cs b/src/database/Dim.Entities/Entities/ProcessType.cs deleted file mode 100644 index b8ff4cc..0000000 --- a/src/database/Dim.Entities/Entities/ProcessType.cs +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************** - * 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.Entities.Enums; -using System.ComponentModel.DataAnnotations; - -namespace Dim.Entities.Entities; - -public class ProcessType -{ - private ProcessType() - { - this.Label = null!; - this.Processes = new HashSet(); - } - - public ProcessType(ProcessTypeId processTypeId) : this() - { - Id = processTypeId; - Label = processTypeId.ToString(); - } - - public ProcessTypeId Id { get; private set; } - - [MaxLength(255)] - public string Label { get; private set; } - - // Navigation properties - public virtual ICollection Processes { get; private set; } -} diff --git a/src/database/Dim.Entities/Enums/ProcessStepStatusId.cs b/src/database/Dim.Entities/Enums/ProcessStepStatusId.cs deleted file mode 100644 index 061e605..0000000 --- a/src/database/Dim.Entities/Enums/ProcessStepStatusId.cs +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************** - * 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 - ********************************************************************************/ - -namespace Dim.Entities.Enums; - -public enum ProcessStepStatusId -{ - TODO = 1, - DONE = 2, - SKIPPED = 3, - FAILED = 4, - DUPLICATE = 5 -} diff --git a/src/database/Dim.Migrations/Dim.Migrations.csproj b/src/database/Dim.Migrations/Dim.Migrations.csproj index 37075ae..45bb901 100644 --- a/src/database/Dim.Migrations/Dim.Migrations.csproj +++ b/src/database/Dim.Migrations/Dim.Migrations.csproj @@ -44,9 +44,9 @@ - - - + + + diff --git a/src/database/Dim.Migrations/Migrations/20250127143528_3-UseProcessWorkerPackage.Designer.cs b/src/database/Dim.Migrations/Migrations/20250127143528_3-UseProcessWorkerPackage.Designer.cs new file mode 100644 index 0000000..342b454 --- /dev/null +++ b/src/database/Dim.Migrations/Migrations/20250127143528_3-UseProcessWorkerPackage.Designer.cs @@ -0,0 +1,591 @@ +/******************************************************************************** + * 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 System; +using Dim.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Dim.Migrations.Migrations +{ + [DbContext(typeof(DimDbContext))] + [Migration("20250127143528_3-UseProcessWorkerPackage")] + partial class _3UseProcessWorkerPackage + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("dim") + .UseCollation("en_US.utf8") + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Dim.Entities.Entities.Process", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LockExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("lock_expiry_date"); + + b.Property("ProcessTypeId") + .HasColumnType("integer") + .HasColumnName("process_type_id"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("uuid") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_processes"); + + b.HasIndex("ProcessTypeId") + .HasDatabaseName("ix_processes_process_type_id"); + + b.ToTable("processes", "dim"); + }); + + modelBuilder.Entity("Dim.Entities.Entities.TechnicalUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ClientId") + .HasColumnType("text") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("ExternalId") + .HasColumnType("uuid") + .HasColumnName("external_id"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.Property("OperationId") + .HasColumnType("uuid") + .HasColumnName("operation_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("ServiceKeyId") + .HasColumnType("uuid") + .HasColumnName("service_key_id"); + + b.Property("TechnicalUserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("technical_user_name"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("tenant_id"); + + b.Property("TokenAddress") + .HasColumnType("text") + .HasColumnName("token_address"); + + b.HasKey("Id") + .HasName("pk_technical_users"); + + b.HasIndex("ProcessId") + .HasDatabaseName("ix_technical_users_process_id"); + + b.HasIndex("TenantId") + .HasDatabaseName("ix_technical_users_tenant_id"); + + b.ToTable("technical_users", "dim"); + }); + + modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("BaseUrl") + .HasColumnType("text") + .HasColumnName("base_url"); + + b.Property("Bpn") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bpn"); + + b.Property("ClientId") + .HasColumnType("text") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("company_name"); + + b.Property("Did") + .HasColumnType("text") + .HasColumnName("did"); + + b.Property("DidDocumentLocation") + .IsRequired() + .HasColumnType("text") + .HasColumnName("did_document_location"); + + b.Property("DidDownloadUrl") + .HasColumnType("text") + .HasColumnName("did_download_url"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.Property("IsIssuer") + .HasColumnType("boolean") + .HasColumnName("is_issuer"); + + b.Property("OperationId") + .HasColumnType("uuid") + .HasColumnName("operation_id"); + + b.Property("OperatorId") + .HasColumnType("uuid") + .HasColumnName("operator_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("TokenAddress") + .HasColumnType("text") + .HasColumnName("token_address"); + + b.Property("WalletId") + .HasColumnType("uuid") + .HasColumnName("wallet_id"); + + b.HasKey("Id") + .HasName("pk_tenants"); + + b.HasIndex("ProcessId") + .HasDatabaseName("ix_tenants_process_id"); + + b.ToTable("tenants", "dim"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("ProcessStepStatusId") + .HasColumnType("integer") + .HasColumnName("process_step_status_id"); + + b.Property("ProcessStepTypeId") + .HasColumnType("integer") + .HasColumnName("process_step_type_id"); + + b.HasKey("Id") + .HasName("pk_process_steps"); + + b.HasIndex("ProcessId") + .HasDatabaseName("ix_process_steps_process_id"); + + b.HasIndex("ProcessStepStatusId") + .HasDatabaseName("ix_process_steps_process_step_status_id"); + + b.HasIndex("ProcessStepTypeId") + .HasDatabaseName("ix_process_steps_process_step_type_id"); + + b.ToTable("process_steps", "dim"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepStatus", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("label"); + + b.HasKey("Id") + .HasName("pk_process_step_statuses"); + + b.ToTable("process_step_statuses", "dim"); + + b.HasData( + new + { + Id = 1, + Label = "TODO" + }, + new + { + Id = 2, + Label = "DONE" + }, + new + { + Id = 3, + Label = "SKIPPED" + }, + new + { + Id = 4, + Label = "FAILED" + }, + new + { + Id = 5, + Label = "DUPLICATE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepType", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("label"); + + b.HasKey("Id") + .HasName("pk_process_step_types"); + + b.ToTable("process_step_types", "dim"); + + b.HasData( + new + { + Id = 1, + Label = "CREATE_WALLET" + }, + new + { + Id = 2, + Label = "CHECK_OPERATION" + }, + new + { + Id = 3, + Label = "GET_COMPANY" + }, + new + { + Id = 4, + Label = "GET_DID_DOCUMENT" + }, + new + { + Id = 5, + Label = "CREATE_STATUS_LIST" + }, + new + { + Id = 6, + Label = "SEND_CALLBACK" + }, + new + { + Id = 7, + Label = "RETRIGGER_CREATE_WALLET" + }, + new + { + Id = 8, + Label = "RETRIGGER_CHECK_OPERATION" + }, + new + { + Id = 9, + Label = "RETRIGGER_GET_COMPANY" + }, + new + { + Id = 10, + Label = "RETRIGGER_GET_DID_DOCUMENT" + }, + new + { + Id = 11, + Label = "RETRIGGER_CREATE_STATUS_LIST" + }, + new + { + Id = 12, + Label = "RETRIGGER_SEND_CALLBACK" + }, + new + { + Id = 100, + Label = "CREATE_TECHNICAL_USER" + }, + new + { + Id = 101, + Label = "GET_TECHNICAL_USER_DATA" + }, + new + { + Id = 102, + Label = "GET_TECHNICAL_USER_SERVICE_KEY" + }, + new + { + Id = 103, + Label = "SEND_TECHNICAL_USER_CREATION_CALLBACK" + }, + new + { + Id = 104, + Label = "RETRIGGER_CREATE_TECHNICAL_USER" + }, + new + { + Id = 105, + Label = "RETRIGGER_GET_TECHNICAL_USER_DATA" + }, + new + { + Id = 106, + Label = "RETRIGGER_GET_TECHNICAL_USER_SERVICE_KEY" + }, + new + { + Id = 107, + Label = "RETRIGGER_SEND_TECHNICAL_USER_CREATION_CALLBACK" + }, + new + { + Id = 200, + Label = "DELETE_TECHNICAL_USER" + }, + new + { + Id = 201, + Label = "SEND_TECHNICAL_USER_DELETION_CALLBACK" + }, + new + { + Id = 202, + Label = "RETRIGGER_DELETE_TECHNICAL_USER" + }, + new + { + Id = 203, + Label = "RETRIGGER_SEND_TECHNICAL_USER_DELETION_CALLBACK" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessType", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("label"); + + b.HasKey("Id") + .HasName("pk_process_types"); + + b.ToTable("process_types", "dim"); + + b.HasData( + new + { + Id = 1, + Label = "SETUP_DIM" + }, + new + { + Id = 2, + Label = "TECHNICAL_USER" + }); + }); + + modelBuilder.Entity("Dim.Entities.Entities.Process", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessType", "ProcessType") + .WithMany("Processes") + .HasForeignKey("ProcessTypeId") + .IsRequired() + .HasConstraintName("fk_processes_process_types_process_type_id"); + + b.Navigation("ProcessType"); + }); + + modelBuilder.Entity("Dim.Entities.Entities.TechnicalUser", b => + { + b.HasOne("Dim.Entities.Entities.Process", "Process") + .WithMany("TechnicalUsers") + .HasForeignKey("ProcessId") + .IsRequired() + .HasConstraintName("fk_technical_users_processes_process_id"); + + b.HasOne("Dim.Entities.Entities.Tenant", "Tenant") + .WithMany("TechnicalUsers") + .HasForeignKey("TenantId") + .IsRequired() + .HasConstraintName("fk_technical_users_tenants_tenant_id"); + + b.Navigation("Process"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => + { + b.HasOne("Dim.Entities.Entities.Process", "Process") + .WithMany("Tenants") + .HasForeignKey("ProcessId") + .IsRequired() + .HasConstraintName("fk_tenants_processes_process_id"); + + b.Navigation("Process"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStep", b => + { + b.HasOne("Dim.Entities.Entities.Process", "Process") + .WithMany("ProcessSteps") + .HasForeignKey("ProcessId") + .IsRequired() + .HasConstraintName("fk_process_steps_processes_process_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepStatus", "ProcessStepStatus") + .WithMany("ProcessSteps") + .HasForeignKey("ProcessStepStatusId") + .IsRequired() + .HasConstraintName("fk_process_steps_process_step_statuses_process_step_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepType", "ProcessStepType") + .WithMany("ProcessSteps") + .HasForeignKey("ProcessStepTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_process_steps_process_step_types_process_step_type_id"); + + b.Navigation("Process"); + + b.Navigation("ProcessStepStatus"); + + b.Navigation("ProcessStepType"); + }); + + modelBuilder.Entity("Dim.Entities.Entities.Process", b => + { + b.Navigation("ProcessSteps"); + + b.Navigation("TechnicalUsers"); + + b.Navigation("Tenants"); + }); + + modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => + { + b.Navigation("TechnicalUsers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepStatus", b => + { + b.Navigation("ProcessSteps"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepType", b => + { + b.Navigation("ProcessSteps"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessType", b => + { + b.Navigation("Processes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/database/Dim.Migrations/Migrations/20250127143528_3-UseProcessWorkerPackage.cs b/src/database/Dim.Migrations/Migrations/20250127143528_3-UseProcessWorkerPackage.cs new file mode 100644 index 0000000..fd6aa9e --- /dev/null +++ b/src/database/Dim.Migrations/Migrations/20250127143528_3-UseProcessWorkerPackage.cs @@ -0,0 +1,68 @@ +/******************************************************************************** + * 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 Microsoft.EntityFrameworkCore.Migrations; +using System; + +#nullable disable + +namespace Dim.Migrations.Migrations +{ + /// + public partial class _3UseProcessWorkerPackage : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_process_steps_process_step_statuses_process_step_status_id", + schema: "dim", + table: "process_steps"); + + migrationBuilder.AddForeignKey( + name: "fk_process_steps_process_step_statuses_process_step_status_id", + schema: "dim", + table: "process_steps", + column: "process_step_status_id", + principalSchema: "dim", + principalTable: "process_step_statuses", + principalColumn: "id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_process_steps_process_step_statuses_process_step_status_id", + schema: "dim", + table: "process_steps"); + + migrationBuilder.AddForeignKey( + name: "fk_process_steps_process_step_statuses_process_step_status_id", + schema: "dim", + table: "process_steps", + column: "process_step_status_id", + principalSchema: "dim", + principalTable: "process_step_statuses", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/database/Dim.Migrations/Migrations/DimDbContextModelSnapshot.cs b/src/database/Dim.Migrations/Migrations/DimDbContextModelSnapshot.cs index 74825a6..f284e5f 100644 --- a/src/database/Dim.Migrations/Migrations/DimDbContextModelSnapshot.cs +++ b/src/database/Dim.Migrations/Migrations/DimDbContextModelSnapshot.cs @@ -1,4 +1,4 @@ -/******************************************************************************** +/******************************************************************************** * Copyright (c) 2024 BMW Group AG * Copyright 2024 SAP SE or an SAP affiliate company and ssi-dim-middle-layer contributors. * @@ -35,7 +35,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder .HasDefaultSchema("dim") .UseCollation("en_US.utf8") - .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("ProductVersion", "8.0.11") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -69,7 +69,158 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("processes", "dim"); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessStep", b => + modelBuilder.Entity("Dim.Entities.Entities.TechnicalUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ClientId") + .HasColumnType("text") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("ExternalId") + .HasColumnType("uuid") + .HasColumnName("external_id"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.Property("OperationId") + .HasColumnType("uuid") + .HasColumnName("operation_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("ServiceKeyId") + .HasColumnType("uuid") + .HasColumnName("service_key_id"); + + b.Property("TechnicalUserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("technical_user_name"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("tenant_id"); + + b.Property("TokenAddress") + .HasColumnType("text") + .HasColumnName("token_address"); + + b.HasKey("Id") + .HasName("pk_technical_users"); + + b.HasIndex("ProcessId") + .HasDatabaseName("ix_technical_users_process_id"); + + b.HasIndex("TenantId") + .HasDatabaseName("ix_technical_users_tenant_id"); + + b.ToTable("technical_users", "dim"); + }); + + modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("BaseUrl") + .HasColumnType("text") + .HasColumnName("base_url"); + + b.Property("Bpn") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bpn"); + + b.Property("ClientId") + .HasColumnType("text") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("company_name"); + + b.Property("Did") + .HasColumnType("text") + .HasColumnName("did"); + + b.Property("DidDocumentLocation") + .IsRequired() + .HasColumnType("text") + .HasColumnName("did_document_location"); + + b.Property("DidDownloadUrl") + .HasColumnType("text") + .HasColumnName("did_download_url"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.Property("IsIssuer") + .HasColumnType("boolean") + .HasColumnName("is_issuer"); + + b.Property("OperationId") + .HasColumnType("uuid") + .HasColumnName("operation_id"); + + b.Property("OperatorId") + .HasColumnType("uuid") + .HasColumnName("operator_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("TokenAddress") + .HasColumnType("text") + .HasColumnName("token_address"); + + b.Property("WalletId") + .HasColumnType("uuid") + .HasColumnName("wallet_id"); + + b.HasKey("Id") + .HasName("pk_tenants"); + + b.HasIndex("ProcessId") + .HasDatabaseName("ix_tenants_process_id"); + + b.ToTable("tenants", "dim"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStep", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -115,7 +266,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("process_steps", "dim"); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessStepStatus", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepStatus", b => { b.Property("Id") .HasColumnType("integer") @@ -160,7 +311,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessStepType", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepType", b => { b.Property("Id") .HasColumnType("integer") @@ -300,7 +451,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessType", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessType", b => { b.Property("Id") .HasColumnType("integer") @@ -330,169 +481,48 @@ protected override void BuildModel(ModelBuilder modelBuilder) }); }); - modelBuilder.Entity("Dim.Entities.Entities.TechnicalUser", b => + modelBuilder.Entity("Dim.Entities.Entities.Process", b => { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("ClientId") - .HasColumnType("text") - .HasColumnName("client_id"); - - b.Property("ClientSecret") - .HasColumnType("bytea") - .HasColumnName("client_secret"); - - b.Property("EncryptionMode") - .HasColumnType("integer") - .HasColumnName("encryption_mode"); - - b.Property("ExternalId") - .HasColumnType("uuid") - .HasColumnName("external_id"); - - b.Property("InitializationVector") - .HasColumnType("bytea") - .HasColumnName("initialization_vector"); - - b.Property("OperationId") - .HasColumnType("uuid") - .HasColumnName("operation_id"); - - b.Property("ProcessId") - .HasColumnType("uuid") - .HasColumnName("process_id"); - - b.Property("ServiceKeyId") - .HasColumnType("uuid") - .HasColumnName("service_key_id"); - - b.Property("TechnicalUserName") + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessType", "ProcessType") + .WithMany("Processes") + .HasForeignKey("ProcessTypeId") .IsRequired() - .HasColumnType("text") - .HasColumnName("technical_user_name"); - - b.Property("TenantId") - .HasColumnType("uuid") - .HasColumnName("tenant_id"); - - b.Property("TokenAddress") - .HasColumnType("text") - .HasColumnName("token_address"); - - b.HasKey("Id") - .HasName("pk_technical_users"); - - b.HasIndex("ProcessId") - .HasDatabaseName("ix_technical_users_process_id"); - - b.HasIndex("TenantId") - .HasDatabaseName("ix_technical_users_tenant_id"); + .HasConstraintName("fk_processes_process_types_process_type_id"); - b.ToTable("technical_users", "dim"); + b.Navigation("ProcessType"); }); - modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => + modelBuilder.Entity("Dim.Entities.Entities.TechnicalUser", b => { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("BaseUrl") - .HasColumnType("text") - .HasColumnName("base_url"); - - b.Property("Bpn") - .IsRequired() - .HasColumnType("text") - .HasColumnName("bpn"); - - b.Property("ClientId") - .HasColumnType("text") - .HasColumnName("client_id"); - - b.Property("ClientSecret") - .HasColumnType("bytea") - .HasColumnName("client_secret"); - - b.Property("CompanyId") - .HasColumnType("uuid") - .HasColumnName("company_id"); - - b.Property("CompanyName") + b.HasOne("Dim.Entities.Entities.Process", "Process") + .WithMany("TechnicalUsers") + .HasForeignKey("ProcessId") .IsRequired() - .HasColumnType("text") - .HasColumnName("company_name"); - - b.Property("Did") - .HasColumnType("text") - .HasColumnName("did"); + .HasConstraintName("fk_technical_users_processes_process_id"); - b.Property("DidDocumentLocation") + b.HasOne("Dim.Entities.Entities.Tenant", "Tenant") + .WithMany("TechnicalUsers") + .HasForeignKey("TenantId") .IsRequired() - .HasColumnType("text") - .HasColumnName("did_document_location"); - - b.Property("DidDownloadUrl") - .HasColumnType("text") - .HasColumnName("did_download_url"); - - b.Property("EncryptionMode") - .HasColumnType("integer") - .HasColumnName("encryption_mode"); - - b.Property("InitializationVector") - .HasColumnType("bytea") - .HasColumnName("initialization_vector"); - - b.Property("IsIssuer") - .HasColumnType("boolean") - .HasColumnName("is_issuer"); - - b.Property("OperationId") - .HasColumnType("uuid") - .HasColumnName("operation_id"); - - b.Property("OperatorId") - .HasColumnType("uuid") - .HasColumnName("operator_id"); - - b.Property("ProcessId") - .HasColumnType("uuid") - .HasColumnName("process_id"); - - b.Property("TokenAddress") - .HasColumnType("text") - .HasColumnName("token_address"); - - b.Property("WalletId") - .HasColumnType("uuid") - .HasColumnName("wallet_id"); - - b.HasKey("Id") - .HasName("pk_tenants"); + .HasConstraintName("fk_technical_users_tenants_tenant_id"); - b.HasIndex("ProcessId") - .HasDatabaseName("ix_tenants_process_id"); + b.Navigation("Process"); - b.ToTable("tenants", "dim"); + b.Navigation("Tenant"); }); - modelBuilder.Entity("Dim.Entities.Entities.Process", b => + modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => { - b.HasOne("Dim.Entities.Entities.ProcessType", "ProcessType") - .WithMany("Processes") - .HasForeignKey("ProcessTypeId") + b.HasOne("Dim.Entities.Entities.Process", "Process") + .WithMany("Tenants") + .HasForeignKey("ProcessId") .IsRequired() - .HasConstraintName("fk_processes_process_types_process_type_id"); + .HasConstraintName("fk_tenants_processes_process_id"); - b.Navigation("ProcessType"); + b.Navigation("Process"); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessStep", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStep", b => { b.HasOne("Dim.Entities.Entities.Process", "Process") .WithMany("ProcessSteps") @@ -500,14 +530,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasConstraintName("fk_process_steps_processes_process_id"); - b.HasOne("Dim.Entities.Entities.ProcessStepStatus", "ProcessStepStatus") + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepStatus", "ProcessStepStatus") .WithMany("ProcessSteps") .HasForeignKey("ProcessStepStatusId") - .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_process_steps_process_step_statuses_process_step_status_id"); - b.HasOne("Dim.Entities.Entities.ProcessStepType", "ProcessStepType") + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepType", "ProcessStepType") .WithMany("ProcessSteps") .HasForeignKey("ProcessStepTypeId") .OnDelete(DeleteBehavior.Cascade) @@ -521,36 +550,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("ProcessStepType"); }); - modelBuilder.Entity("Dim.Entities.Entities.TechnicalUser", b => - { - b.HasOne("Dim.Entities.Entities.Process", "Process") - .WithMany("TechnicalUsers") - .HasForeignKey("ProcessId") - .IsRequired() - .HasConstraintName("fk_technical_users_processes_process_id"); - - b.HasOne("Dim.Entities.Entities.Tenant", "Tenant") - .WithMany("TechnicalUsers") - .HasForeignKey("TenantId") - .IsRequired() - .HasConstraintName("fk_technical_users_tenants_tenant_id"); - - b.Navigation("Process"); - - b.Navigation("Tenant"); - }); - - modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => - { - b.HasOne("Dim.Entities.Entities.Process", "Process") - .WithMany("Tenants") - .HasForeignKey("ProcessId") - .IsRequired() - .HasConstraintName("fk_tenants_processes_process_id"); - - b.Navigation("Process"); - }); - modelBuilder.Entity("Dim.Entities.Entities.Process", b => { b.Navigation("ProcessSteps"); @@ -560,24 +559,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Tenants"); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessStepStatus", b => + modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => { - b.Navigation("ProcessSteps"); + b.Navigation("TechnicalUsers"); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessStepType", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepStatus", b => { b.Navigation("ProcessSteps"); }); - modelBuilder.Entity("Dim.Entities.Entities.ProcessType", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessStepType", b => { - b.Navigation("Processes"); + b.Navigation("ProcessSteps"); }); - modelBuilder.Entity("Dim.Entities.Entities.Tenant", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities.ProcessType", b => { - b.Navigation("TechnicalUsers"); + b.Navigation("Processes"); }); #pragma warning restore 612, 618 } diff --git a/src/database/Dim.Migrations/Seeder/BatchInsertSeeder.cs b/src/database/Dim.Migrations/Seeder/BatchInsertSeeder.cs index da9b66d..c2b8889 100644 --- a/src/database/Dim.Migrations/Seeder/BatchInsertSeeder.cs +++ b/src/database/Dim.Migrations/Seeder/BatchInsertSeeder.cs @@ -20,8 +20,10 @@ using Dim.Entities; using Dim.Entities.Entities; +using Dim.Entities.Enums; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities; using Org.Eclipse.TractusX.Portal.Backend.Framework.Seeding; namespace Dim.Migrations.Seeder; @@ -48,7 +50,7 @@ public async Task ExecuteAsync(CancellationToken cancellationToken) logger.LogInformation("Start BaseEntityBatch Seeder"); await SeedTable("tenants", x => x.Id, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); - await SeedTable("process_steps", x => x.Id, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); + await SeedTable>("process_steps", x => x.Id, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); await SeedTable("processes", x => x.Id, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); await SeedTable("technical_users", x => x.Id, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); diff --git a/src/processes/DimProcess.Executor/DependencyInjection/DimProcessCollectionExtensions.cs b/src/processes/DimProcess.Executor/DependencyInjection/DimProcessCollectionExtensions.cs index 741d88c..08a758d 100644 --- a/src/processes/DimProcess.Executor/DependencyInjection/DimProcessCollectionExtensions.cs +++ b/src/processes/DimProcess.Executor/DependencyInjection/DimProcessCollectionExtensions.cs @@ -18,10 +18,11 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +using Dim.Entities.Enums; using DimProcess.Library.DependencyInjection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Processes.Worker.Library; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Worker.Library; namespace DimProcess.Executor.DependencyInjection; @@ -29,11 +30,11 @@ public static class DimProcessCollectionExtensions { public static IServiceCollection AddDimProcessExecutor(this IServiceCollection services, IConfiguration config) => services - .AddTransient() + .AddTransient, DimProcessTypeExecutor>() .AddDimProcessHandler(config); public static IServiceCollection AddTechnicalUserProcessExecutor(this IServiceCollection services, IConfiguration config) => services - .AddTransient() + .AddTransient, TechnicalUserProcessTypeExecutor>() .AddTechnicalUserProcessHandler(config); } diff --git a/src/processes/DimProcess.Executor/DimProcess.Executor.csproj b/src/processes/DimProcess.Executor/DimProcess.Executor.csproj index 214c8fc..800c751 100644 --- a/src/processes/DimProcess.Executor/DimProcess.Executor.csproj +++ b/src/processes/DimProcess.Executor/DimProcess.Executor.csproj @@ -31,11 +31,11 @@ + - diff --git a/src/processes/DimProcess.Executor/DimProcessTypeExecutor.cs b/src/processes/DimProcess.Executor/DimProcessTypeExecutor.cs index e890d10..74f6ab8 100644 --- a/src/processes/DimProcess.Executor/DimProcessTypeExecutor.cs +++ b/src/processes/DimProcess.Executor/DimProcessTypeExecutor.cs @@ -24,7 +24,8 @@ using Dim.Entities.Extensions; using DimProcess.Library; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; -using Processes.Worker.Library; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Worker.Library; using System.Collections.Immutable; namespace DimProcess.Executor; @@ -32,7 +33,7 @@ namespace DimProcess.Executor; public class DimProcessTypeExecutor( IDimRepositories dimRepositories, IDimProcessHandler dimProcessHandler) - : IProcessTypeExecutor + : IProcessTypeExecutor { private readonly IEnumerable _executableProcessSteps = ImmutableArray.Create( ProcessStepTypeId.CREATE_WALLET, @@ -50,7 +51,7 @@ public class DimProcessTypeExecutor( public IEnumerable GetExecutableStepTypeIds() => _executableProcessSteps; public ValueTask IsLockRequested(ProcessStepTypeId processStepTypeId) => new(false); - public async ValueTask InitializeProcess(Guid processId, IEnumerable processStepTypeIds) + public async ValueTask.InitializationResult> InitializeProcess(Guid processId, IEnumerable processStepTypeIds) { var (exists, tenantId, companyName, bpn) = await dimRepositories.GetInstance().GetTenantDataForProcessId(processId).ConfigureAwait(ConfigureAwaitOptions.None); if (!exists) @@ -60,10 +61,10 @@ public class DimProcessTypeExecutor( _tenantId = tenantId; _tenantName = $"{bpn}{companyName}"; - return new IProcessTypeExecutor.InitializationResult(false, null); + return new IProcessTypeExecutor.InitializationResult(false, null); } - public async ValueTask ExecuteProcessStep(ProcessStepTypeId processStepTypeId, IEnumerable processStepTypeIds, CancellationToken cancellationToken) + public async ValueTask.StepExecutionResult> ExecuteProcessStep(ProcessStepTypeId processStepTypeId, IEnumerable processStepTypeIds, CancellationToken cancellationToken) { if (_tenantId == Guid.Empty || _tenantName is null) { @@ -100,7 +101,7 @@ public class DimProcessTypeExecutor( modified = true; } - return new IProcessTypeExecutor.StepExecutionResult(modified, stepStatusId, nextStepTypeIds, null, processMessage); + return new IProcessTypeExecutor.StepExecutionResult(modified, stepStatusId, nextStepTypeIds, null, processMessage); } private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerable? nextSteps) ProcessError(Exception ex, ProcessStepTypeId processStepTypeId) diff --git a/src/processes/DimProcess.Executor/TechnicalUserProcessTypeExecutor.cs b/src/processes/DimProcess.Executor/TechnicalUserProcessTypeExecutor.cs index 70ca15e..038d0fa 100644 --- a/src/processes/DimProcess.Executor/TechnicalUserProcessTypeExecutor.cs +++ b/src/processes/DimProcess.Executor/TechnicalUserProcessTypeExecutor.cs @@ -24,7 +24,8 @@ using Dim.Entities.Extensions; using DimProcess.Library; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; -using Processes.Worker.Library; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Worker.Library; using System.Collections.Immutable; namespace DimProcess.Executor; @@ -32,7 +33,7 @@ namespace DimProcess.Executor; public class TechnicalUserProcessTypeExecutor( IDimRepositories dimRepositories, ITechnicalUserProcessHandler technicalUserProcessHandler) - : IProcessTypeExecutor + : IProcessTypeExecutor { private readonly IEnumerable _executableProcessSteps = ImmutableArray.Create( ProcessStepTypeId.CREATE_TECHNICAL_USER, @@ -49,7 +50,7 @@ public class TechnicalUserProcessTypeExecutor( public IEnumerable GetExecutableStepTypeIds() => _executableProcessSteps; public ValueTask IsLockRequested(ProcessStepTypeId processStepTypeId) => new(false); - public async ValueTask InitializeProcess(Guid processId, IEnumerable processStepTypeIds) + public async ValueTask.InitializationResult> InitializeProcess(Guid processId, IEnumerable processStepTypeIds) { var (exists, technicalUserId) = await dimRepositories.GetInstance().GetTenantDataForTechnicalUserProcessId(processId).ConfigureAwait(ConfigureAwaitOptions.None); if (!exists) @@ -58,10 +59,10 @@ public class TechnicalUserProcessTypeExecutor( } _technicalUserId = technicalUserId; - return new IProcessTypeExecutor.InitializationResult(false, null); + return new IProcessTypeExecutor.InitializationResult(false, null); } - public async ValueTask ExecuteProcessStep(ProcessStepTypeId processStepTypeId, IEnumerable processStepTypeIds, CancellationToken cancellationToken) + public async ValueTask.StepExecutionResult> ExecuteProcessStep(ProcessStepTypeId processStepTypeId, IEnumerable processStepTypeIds, CancellationToken cancellationToken) { if (_technicalUserId == Guid.Empty) { @@ -98,7 +99,7 @@ public class TechnicalUserProcessTypeExecutor( modified = true; } - return new IProcessTypeExecutor.StepExecutionResult(modified, stepStatusId, nextStepTypeIds, null, processMessage); + return new IProcessTypeExecutor.StepExecutionResult(modified, stepStatusId, nextStepTypeIds, null, processMessage); } private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerable? nextSteps) ProcessError(Exception ex, ProcessStepTypeId processStepTypeId) diff --git a/src/processes/DimProcess.Library/DimProcess.Library.csproj b/src/processes/DimProcess.Library/DimProcess.Library.csproj index 4cbbf96..8d9e7b0 100644 --- a/src/processes/DimProcess.Library/DimProcess.Library.csproj +++ b/src/processes/DimProcess.Library/DimProcess.Library.csproj @@ -32,8 +32,8 @@ - - + + diff --git a/src/processes/DimProcess.Library/DimProcessHandler.cs b/src/processes/DimProcess.Library/DimProcessHandler.cs index d484c58..5aa089a 100644 --- a/src/processes/DimProcess.Library/DimProcessHandler.cs +++ b/src/processes/DimProcess.Library/DimProcessHandler.cs @@ -31,6 +31,7 @@ using Microsoft.Extensions.Options; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; using System.Text.Json; namespace DimProcess.Library; diff --git a/src/processes/DimProcess.Library/IDimProcessHandler.cs b/src/processes/DimProcess.Library/IDimProcessHandler.cs index 964da62..9dcce8c 100644 --- a/src/processes/DimProcess.Library/IDimProcessHandler.cs +++ b/src/processes/DimProcess.Library/IDimProcessHandler.cs @@ -19,6 +19,7 @@ ********************************************************************************/ using Dim.Entities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; namespace DimProcess.Library; diff --git a/src/processes/DimProcess.Library/ITechnicalUserProcessHandler.cs b/src/processes/DimProcess.Library/ITechnicalUserProcessHandler.cs index a0e58ff..4c19667 100644 --- a/src/processes/DimProcess.Library/ITechnicalUserProcessHandler.cs +++ b/src/processes/DimProcess.Library/ITechnicalUserProcessHandler.cs @@ -19,6 +19,7 @@ ********************************************************************************/ using Dim.Entities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; namespace DimProcess.Library; diff --git a/src/processes/DimProcess.Library/TechnicalUserProcessHandler.cs b/src/processes/DimProcess.Library/TechnicalUserProcessHandler.cs index 0f5ec0d..928613d 100644 --- a/src/processes/DimProcess.Library/TechnicalUserProcessHandler.cs +++ b/src/processes/DimProcess.Library/TechnicalUserProcessHandler.cs @@ -30,6 +30,7 @@ using Microsoft.Extensions.Options; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; namespace DimProcess.Library; diff --git a/src/processes/Processes.Library/ManualProcessStepData.cs b/src/processes/Processes.Library/ManualProcessStepData.cs deleted file mode 100644 index 5cc0011..0000000 --- a/src/processes/Processes.Library/ManualProcessStepData.cs +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************** - * 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.DbAccess; -using Dim.Entities.Entities; -using Dim.Entities.Enums; - -namespace Dim.Processes.Library; - -public record ManualProcessStepData( - ProcessStepTypeId ProcessStepTypeId, - Process Process, - IEnumerable ProcessSteps, - IDimRepositories PortalRepositories -); diff --git a/src/processes/Processes.Library/ManualProcessStepDataExtensions.cs b/src/processes/Processes.Library/ManualProcessStepDataExtensions.cs deleted file mode 100644 index f6f8522..0000000 --- a/src/processes/Processes.Library/ManualProcessStepDataExtensions.cs +++ /dev/null @@ -1,140 +0,0 @@ -/******************************************************************************** - * 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.DbAccess; -using Dim.DbAccess.Models; -using Dim.DbAccess.Repositories; -using Dim.Entities.Entities; -using Dim.Entities.Enums; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; - -namespace Dim.Processes.Library; - -public static class VerifyProcessDataExtensions -{ - public static ManualProcessStepData CreateManualProcessData( - this VerifyProcessData? processData, - ProcessStepTypeId processStepTypeId, - IDimRepositories portalRepositories, - Func getProcessEntityName) - { - if (processData is null) - { - throw new NotFoundException($"{getProcessEntityName()} does not exist"); - } - - if (processData.Process == null) - { - throw new ConflictException($"{getProcessEntityName()} is not associated with any process"); - } - - if (processData.Process.IsLocked()) - { - throw new ConflictException($"process {processData.Process.Id} associated with {getProcessEntityName()} is locked, lock expiry is set to {processData.Process.LockExpiryDate}"); - } - - if (processData.ProcessSteps == null) - { - throw new UnexpectedConditionException("processSteps should never be null here"); - } - - if (processData.ProcessSteps.Any(step => step.ProcessStepStatusId != ProcessStepStatusId.TODO)) - { - throw new UnexpectedConditionException($"processSteps should never have any other status than TODO here"); - } - - if (processData.ProcessSteps.All(step => step.ProcessStepTypeId != processStepTypeId)) - { - throw new ConflictException($"{getProcessEntityName()}, process step {processStepTypeId} is not eligible to run"); - } - - return new(processStepTypeId, processData.Process, processData.ProcessSteps, portalRepositories); - } -} - -public static class ManualProcessStepDataExtensions -{ - public static void RequestLock(this ManualProcessStepData context, DateTimeOffset lockExpiryDate) - { - context.PortalRepositories.Attach(context.Process); - - var isLocked = context.Process.TryLock(lockExpiryDate); - if (!isLocked) - { - throw new UnexpectedConditionException("process TryLock should never fail here"); - } - } - - public static void SkipProcessSteps(this ManualProcessStepData context, IEnumerable processStepTypeIds) => - context.PortalRepositories.GetInstance() - .AttachAndModifyProcessSteps( - context.ProcessSteps - .Where(step => step.ProcessStepTypeId != context.ProcessStepTypeId) - .GroupBy(step => step.ProcessStepTypeId) - .IntersectBy(processStepTypeIds, group => group.Key) - .SelectMany(group => ModifyStepStatusRange(group, ProcessStepStatusId.SKIPPED))); - - public static void SkipProcessStepsExcept(this ManualProcessStepData context, IEnumerable processStepTypeIds) => - context.PortalRepositories.GetInstance() - .AttachAndModifyProcessSteps( - context.ProcessSteps - .Where(step => step.ProcessStepTypeId != context.ProcessStepTypeId) - .GroupBy(step => step.ProcessStepTypeId) - .ExceptBy(processStepTypeIds, group => group.Key) - .SelectMany(group => ModifyStepStatusRange(group, ProcessStepStatusId.SKIPPED))); - - public static void ScheduleProcessSteps(this ManualProcessStepData context, IEnumerable processStepTypeIds) => - context.PortalRepositories.GetInstance() - .CreateProcessStepRange( - processStepTypeIds - .Except(context.ProcessSteps.Select(step => step.ProcessStepTypeId)) - .Select(stepTypeId => (stepTypeId, ProcessStepStatusId.TODO, context.Process.Id))); - - public static void FinalizeProcessStep(this ManualProcessStepData context) - { - context.PortalRepositories.GetInstance().AttachAndModifyProcessSteps( - ModifyStepStatusRange(context.ProcessSteps.Where(step => step.ProcessStepTypeId == context.ProcessStepTypeId), ProcessStepStatusId.DONE)); - - context.PortalRepositories.Attach(context.Process); - if (!context.Process.ReleaseLock()) - { - context.Process.UpdateVersion(); - } - } - - private static IEnumerable<(Guid, Action?, Action)> ModifyStepStatusRange(IEnumerable steps, ProcessStepStatusId processStepStatusId) - { - var firstStep = steps.FirstOrDefault(); - - if (firstStep == null) - yield break; - - foreach (var step in steps) - { - yield return ( - step.Id, - null, - ps => ps.ProcessStepStatusId = ps.Id == firstStep.Id - ? processStepStatusId - : ProcessStepStatusId.DUPLICATE); - } - } -} diff --git a/src/processes/Processes.Library/Processes.Library.csproj b/src/processes/Processes.Library/Processes.Library.csproj deleted file mode 100644 index a55a5c6..0000000 --- a/src/processes/Processes.Library/Processes.Library.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - Dim.Processes.Library - Dim.Processes.Library - net8.0 - enable - enable - 76a1cf69-39e1-43a7-b6a7-fef83be5359f - - - - - - - - diff --git a/src/processes/Processes.Worker.Library/IProcessExecutor.cs b/src/processes/Processes.Worker.Library/IProcessExecutor.cs deleted file mode 100644 index 22bb752..0000000 --- a/src/processes/Processes.Worker.Library/IProcessExecutor.cs +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************** - * 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.Entities.Enums; - -namespace Processes.Worker.Library; - -public interface IProcessExecutor -{ - enum ProcessExecutionResult - { - SaveRequested = 1, - LockRequested = 2, - Unmodified = 3 - } - IAsyncEnumerable ExecuteProcess(Guid processId, ProcessTypeId processTypeId, CancellationToken cancellationToken); - IEnumerable GetRegisteredProcessTypeIds(); - IEnumerable GetExecutableStepTypeIds(); -} diff --git a/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs b/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs deleted file mode 100644 index 213de9f..0000000 --- a/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************** - * 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.Entities.Enums; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; - -namespace Processes.Worker.Library; - -public interface IProcessTypeExecutor -{ - record InitializationResult(bool Modified, IEnumerable? ScheduleStepTypeIds); - record StepExecutionResult(bool Modified, ProcessStepStatusId ProcessStepStatusId, IEnumerable? ScheduleStepTypeIds, IEnumerable? SkipStepTypeIds, string? ProcessMessage); - - ValueTask InitializeProcess(Guid processId, IEnumerable processStepTypeIds); - ValueTask IsLockRequested(ProcessStepTypeId processStepTypeId); - - /// - /// tbd - /// - /// - /// - /// - /// Is thrown if entity is not found - /// Is thrown if ... - /// - ValueTask ExecuteProcessStep(ProcessStepTypeId processStepTypeId, IEnumerable processStepTypeIds, CancellationToken cancellationToken); - bool IsExecutableStepTypeId(ProcessStepTypeId processStepTypeId); - ProcessTypeId GetProcessTypeId(); - IEnumerable GetExecutableStepTypeIds(); -} diff --git a/src/processes/Processes.Worker.Library/ProcessExecutionService.cs b/src/processes/Processes.Worker.Library/ProcessExecutionService.cs deleted file mode 100644 index 6f0e449..0000000 --- a/src/processes/Processes.Worker.Library/ProcessExecutionService.cs +++ /dev/null @@ -1,146 +0,0 @@ -/******************************************************************************** - * 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.DbAccess; -using Dim.DbAccess.Repositories; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; - -namespace Processes.Worker.Library; - -/// -/// Service that reads all open/pending processSteps of a checklist and triggers their execution. -/// -public class ProcessExecutionService -{ - private readonly IServiceScopeFactory _serviceScopeFactory; - private readonly IDateTimeProvider _dateTimeProvider; - private readonly ProcessExecutionServiceSettings _settings; - private readonly ILogger _logger; - - /// - /// Creates a new instance of - /// - /// access to the services - /// date time provider - /// access to the options - /// the logger - public ProcessExecutionService( - IServiceScopeFactory serviceScopeFactory, - IDateTimeProvider dateTimeProvider, - IOptions options, - ILogger logger) - { - _serviceScopeFactory = serviceScopeFactory; - _dateTimeProvider = dateTimeProvider; - _settings = options.Value; - _logger = logger; - } - - /// - /// Handles the checklist processing - /// - /// Cancellation Token - public async Task ExecuteAsync(CancellationToken stoppingToken) - { - try - { - using var processServiceScope = _serviceScopeFactory.CreateScope(); - var executorRepositories = processServiceScope.ServiceProvider.GetRequiredService(); - var processExecutor = processServiceScope.ServiceProvider.GetRequiredService(); - - using var outerLoopScope = _serviceScopeFactory.CreateScope(); - var outerLoopRepositories = outerLoopScope.ServiceProvider.GetRequiredService(); - - var lockExpiryTime = new TimeSpan(_settings.LockExpirySeconds * 10000000L); - var activeProcesses = outerLoopRepositories.GetInstance().GetActiveProcesses(processExecutor.GetRegisteredProcessTypeIds(), processExecutor.GetExecutableStepTypeIds(), _dateTimeProvider.OffsetNow); - await foreach (var process in activeProcesses.WithCancellation(stoppingToken).ConfigureAwait(false)) - { - try - { - if (process.IsLocked()) - { - _logger.LogInformation("skipping locked process {processId} type {processType}, lock expires at {lockExpireDate}", process.Id, process.ProcessTypeId, process.LockExpiryDate); - continue; - } - _logger.LogInformation("start processing process {processId} type {processType}", process.Id, process.ProcessTypeId); - - bool EnsureLock() - { - if (process.IsLocked()) - { - return false; - } - var isLocked = process.TryLock(_dateTimeProvider.OffsetNow.Add(lockExpiryTime)); - if (!isLocked) - { - throw new UnexpectedConditionException("process TryLock should never fail here"); - } - return true; - } - - bool UpdateVersion() - { - if (!process.IsLocked()) - { - process.UpdateVersion(); - } - return true; - } - - await foreach (var executionResult in processExecutor.ExecuteProcess(process.Id, process.ProcessTypeId, stoppingToken).ConfigureAwait(false)) - { - if (executionResult switch - { - IProcessExecutor.ProcessExecutionResult.LockRequested => EnsureLock(), - IProcessExecutor.ProcessExecutionResult.SaveRequested => UpdateVersion(), - _ => false - }) - { - await executorRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); - } - executorRepositories.Clear(); - } - - if (process.ReleaseLock()) - { - await executorRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); - executorRepositories.Clear(); - } - _logger.LogInformation("finished processing process {processId}", process.Id); - } - catch (Exception ex) when (ex is not SystemException) - { - _logger.LogInformation(ex, "error processing process {processId} type {processType}: {message}", process.Id, process.ProcessTypeId, ex.Message); - executorRepositories.Clear(); - } - } - } - catch (Exception ex) - { - Environment.ExitCode = 1; - _logger.LogError(ex, "processing failed with following Exception {ExceptionMessage}", ex.Message); - } - } -} diff --git a/src/processes/Processes.Worker.Library/ProcessExecutionServiceExtensions.cs b/src/processes/Processes.Worker.Library/ProcessExecutionServiceExtensions.cs deleted file mode 100644 index 8fd0c74..0000000 --- a/src/processes/Processes.Worker.Library/ProcessExecutionServiceExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************** - * 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 Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider; - -namespace Processes.Worker.Library; - -public static class ProcessExecutionServiceExtensions -{ - public static IServiceCollection AddProcessExecutionService(this IServiceCollection services, IConfigurationSection section) - { - services.AddOptions().Bind(section); - services - .AddTransient() - .AddTransient() - .AddTransient(); - return services; - } -} diff --git a/src/processes/Processes.Worker.Library/ProcessExecutionServiceSettings.cs b/src/processes/Processes.Worker.Library/ProcessExecutionServiceSettings.cs deleted file mode 100644 index 3f31291..0000000 --- a/src/processes/Processes.Worker.Library/ProcessExecutionServiceSettings.cs +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************** - * 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 System.ComponentModel.DataAnnotations; - -namespace Processes.Worker.Library; - -public class ProcessExecutionServiceSettings -{ - [Required] - public int LockExpirySeconds { get; set; } -} diff --git a/src/processes/Processes.Worker.Library/ProcessExecutor.cs b/src/processes/Processes.Worker.Library/ProcessExecutor.cs deleted file mode 100644 index 2c31944..0000000 --- a/src/processes/Processes.Worker.Library/ProcessExecutor.cs +++ /dev/null @@ -1,215 +0,0 @@ -/******************************************************************************** - * 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.DbAccess; -using Dim.DbAccess.Repositories; -using Dim.Entities.Enums; -using Microsoft.Extensions.Logging; -using Org.Eclipse.TractusX.Portal.Backend.Framework.Async; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; -using System.Collections.Immutable; -using System.Runtime.CompilerServices; - -namespace Processes.Worker.Library; - -public class ProcessExecutor : IProcessExecutor -{ - private readonly ImmutableDictionary _executors; - private readonly IProcessStepRepository _processStepRepository; - private readonly ILogger _logger; - - public ProcessExecutor(IEnumerable executors, IDimRepositories portalRepositories, ILogger logger) - { - _processStepRepository = portalRepositories.GetInstance(); - _executors = executors.ToImmutableDictionary(executor => executor.GetProcessTypeId()); - _logger = logger; - } - - public IEnumerable GetRegisteredProcessTypeIds() => _executors.Keys; - public IEnumerable GetExecutableStepTypeIds() => _executors.Values.SelectMany(executor => executor.GetExecutableStepTypeIds()); - - public async IAsyncEnumerable ExecuteProcess(Guid processId, ProcessTypeId processTypeId, [EnumeratorCancellation] CancellationToken cancellationToken) - { - if (!_executors.TryGetValue(processTypeId, out var executor)) - { - throw new UnexpectedConditionException($"processType {processTypeId} is not a registered executable processType."); - } - - var allSteps = await _processStepRepository - .GetProcessStepData(processId) - .PreSortedGroupBy(x => x.ProcessStepTypeId, x => x.ProcessStepId) - .ToDictionaryAsync(g => g.Key, g => g.AsEnumerable(), cancellationToken) - .ConfigureAwait(false); - - var context = new ProcessContext( - processId, - allSteps, - new ProcessStepTypeSet(allSteps.Keys.Where(x => executor.IsExecutableStepTypeId(x))), - executor); - - var (modified, initialStepTypeIds) = await executor.InitializeProcess(processId, context.AllSteps.Keys).ConfigureAwait(false); - - modified |= ScheduleProcessStepTypeIds(initialStepTypeIds, context); - - yield return modified - ? IProcessExecutor.ProcessExecutionResult.SaveRequested - : IProcessExecutor.ProcessExecutionResult.Unmodified; - - while (context.ExecutableStepTypeIds.TryGetNext(out var stepTypeId)) - { - if (await executor.IsLockRequested(stepTypeId).ConfigureAwait(false)) - { - yield return IProcessExecutor.ProcessExecutionResult.LockRequested; - } - - ProcessStepStatusId resultStepStatusId; - IEnumerable? scheduleStepTypeIds; - IEnumerable? skipStepTypeIds; - string? processMessage; - bool success; - try - { - (modified, resultStepStatusId, scheduleStepTypeIds, skipStepTypeIds, processMessage) = await executor.ExecuteProcessStep(stepTypeId, context.AllSteps.Keys, cancellationToken).ConfigureAwait(false); - success = true; - } - catch (Exception e) when (e is not SystemException) - { - resultStepStatusId = ProcessStepStatusId.FAILED; - processMessage = $"{e.GetType()}: {e.Message}"; - scheduleStepTypeIds = null; - skipStepTypeIds = null; - modified = false; - success = false; - } - if (!success) - { - yield return IProcessExecutor.ProcessExecutionResult.Unmodified; - } - modified |= SetProcessStepStatus(stepTypeId, resultStepStatusId, context, processMessage); - modified |= SkipProcessStepTypeIds(skipStepTypeIds, context); - modified |= ScheduleProcessStepTypeIds(scheduleStepTypeIds, context); - - yield return modified - ? IProcessExecutor.ProcessExecutionResult.SaveRequested - : IProcessExecutor.ProcessExecutionResult.Unmodified; - } - } - - private bool ScheduleProcessStepTypeIds(IEnumerable? scheduleStepTypeIds, ProcessContext context) - { - if (scheduleStepTypeIds == null || !scheduleStepTypeIds.Any()) - { - return false; - } - - var newStepTypeIds = scheduleStepTypeIds.Except(context.AllSteps.Keys).ToList(); - if (!newStepTypeIds.Any()) - { - return false; - } - foreach (var newStep in _processStepRepository.CreateProcessStepRange(newStepTypeIds.Select(stepTypeId => (stepTypeId, ProcessStepStatusId.TODO, context.ProcessId)))) - { - context.AllSteps.Add(newStep.ProcessStepTypeId, new[] { newStep.Id }); - if (context.Executor.IsExecutableStepTypeId(newStep.ProcessStepTypeId)) - { - context.ExecutableStepTypeIds.Add(newStep.ProcessStepTypeId); - } - } - return true; - } - - private bool SkipProcessStepTypeIds(IEnumerable? skipStepTypeIds, ProcessContext context) - { - if (skipStepTypeIds == null || !skipStepTypeIds.Any()) - { - return false; - } - var modified = false; - foreach (var skipStepTypeId in skipStepTypeIds) - { - var skippedStep = SetProcessStepStatus(skipStepTypeId, ProcessStepStatusId.SKIPPED, context, null); - if (skippedStep) - { - _logger.LogInformation("Skipped step {SkipStepTypeId} for process {ProcessId}", skipStepTypeId, context.ProcessId); - } - - modified |= skippedStep; - } - return modified; - } - - private bool SetProcessStepStatus(ProcessStepTypeId stepTypeId, ProcessStepStatusId stepStatusId, ProcessContext context, string? processMessage) - { - if ((stepStatusId == ProcessStepStatusId.TODO && processMessage == null) || !context.AllSteps.Remove(stepTypeId, out var stepIds)) - { - return false; - } - - var isFirst = true; - foreach (var stepId in stepIds) - { - _processStepRepository.AttachAndModifyProcessStep(stepId, null, step => - { - step.ProcessStepStatusId = isFirst ? stepStatusId : ProcessStepStatusId.DUPLICATE; - step.Message = processMessage; - }); - isFirst = false; - } - if (context.Executor.IsExecutableStepTypeId(stepTypeId)) - { - context.ExecutableStepTypeIds.Remove(stepTypeId); - } - return true; - } - - private sealed record ProcessContext( - Guid ProcessId, - IDictionary> AllSteps, - ProcessStepTypeSet ExecutableStepTypeIds, - IProcessTypeExecutor Executor - ); - - private sealed class ProcessStepTypeSet - { - private readonly HashSet _items; - - public ProcessStepTypeSet(IEnumerable items) - { - _items = new HashSet(items); - } - - public bool TryGetNext(out ProcessStepTypeId item) - { - using var enumerator = _items.GetEnumerator(); - if (!enumerator.MoveNext()) - { - item = default; - return false; - } - item = enumerator.Current; - _items.Remove(item); - return true; - } - - public void Add(ProcessStepTypeId item) => _items.Add(item); - - public void Remove(ProcessStepTypeId item) => _items.Remove(item); - } -} diff --git a/src/processes/Processes.Worker.Library/Processes.Worker.Library.csproj b/src/processes/Processes.Worker.Library/Processes.Worker.Library.csproj deleted file mode 100644 index 778ff39..0000000 --- a/src/processes/Processes.Worker.Library/Processes.Worker.Library.csproj +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - Processes.Worker.Library - Processes.Worker.Library - net8.0 - enable - enable - - - - - - - - - - - - - - - - - - diff --git a/src/processes/Processes.Worker/Processes.Worker.csproj b/src/processes/Processes.Worker/Processes.Worker.csproj index 753bedc..d313b39 100644 --- a/src/processes/Processes.Worker/Processes.Worker.csproj +++ b/src/processes/Processes.Worker/Processes.Worker.csproj @@ -35,13 +35,12 @@ - - - + + diff --git a/src/processes/Processes.Worker/Program.cs b/src/processes/Processes.Worker/Program.cs index 8420912..5b3f3eb 100644 --- a/src/processes/Processes.Worker/Program.cs +++ b/src/processes/Processes.Worker/Program.cs @@ -19,12 +19,13 @@ ********************************************************************************/ using Dim.DbAccess.DependencyInjection; +using Dim.Entities.Enums; using DimProcess.Executor.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Org.Eclipse.TractusX.Portal.Backend.Framework.Logging; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Worker.Library; using Org.Eclipse.TractusX.Portal.Backend.Framework.Token; -using Processes.Worker.Library; using Serilog; LoggingExtensions.EnsureInitialized(); @@ -38,7 +39,7 @@ services .AddTransient() .AddDatabase(hostContext.Configuration) - .AddProcessExecutionService(hostContext.Configuration.GetSection("Processes")) + .AddProcessExecutionService(hostContext.Configuration.GetSection("Processes")) .AddDimProcessExecutor(hostContext.Configuration) .AddTechnicalUserProcessExecutor(hostContext.Configuration); }) @@ -55,7 +56,7 @@ }; Log.Information("Start processing"); - var workerInstance = host.Services.GetRequiredService(); + var workerInstance = host.Services.GetRequiredService>(); await workerInstance.ExecuteAsync(tokenSource.Token).ConfigureAwait(ConfigureAwaitOptions.None); Log.Information("Execution finished shutting down"); } diff --git a/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs b/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs index e8cb076..8f5d67a 100644 --- a/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs +++ b/src/web/Dim.Web/BusinessLogic/DimBusinessLogic.cs @@ -26,12 +26,14 @@ using Dim.DbAccess.Repositories; using Dim.Entities.Enums; using Dim.Entities.Extensions; -using Dim.Processes.Library; using Dim.Web.ErrorHandling; using Dim.Web.Models; using Microsoft.Extensions.Options; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Extensions; using System.Text.RegularExpressions; namespace Dim.Web.BusinessLogic; @@ -53,7 +55,7 @@ public async Task StartSetupDim(string companyName, string bpn, string didDocume throw ConflictException.Create(DimErrors.TENANT_ALREADY_EXISTS, new ErrorParameter[] { new("companyName", companyName), new("bpn", bpn) }); } - var processStepRepository = dimRepositories.GetInstance(); + var processStepRepository = dimRepositories.GetInstance>(); var processId = processStepRepository.CreateProcess(ProcessTypeId.SETUP_DIM).Id; processStepRepository.CreateProcessStep(ProcessStepTypeId.CREATE_WALLET, ProcessStepStatusId.TODO, processId); @@ -133,7 +135,7 @@ public async Task CreateTechnicalUser(string bpn, TechnicalUserData technicalUse throw NotFoundException.Create(DimErrors.NO_COMPANY_FOR_BPN, new ErrorParameter[] { new("bpn", bpn) }); } - var processStepRepository = dimRepositories.GetInstance(); + var processStepRepository = dimRepositories.GetInstance>(); var processId = processStepRepository.CreateProcess(ProcessTypeId.TECHNICAL_USER).Id; processStepRepository.CreateProcessStep(ProcessStepTypeId.CREATE_TECHNICAL_USER, ProcessStepStatusId.TODO, processId); @@ -152,7 +154,7 @@ public async Task DeleteTechnicalUser(string bpn, TechnicalUserData technicalUse throw NotFoundException.Create(DimErrors.NO_TECHNICAL_USER_FOUND, new ErrorParameter[] { new("bpn", bpn) }); } - var processStepRepository = dimRepositories.GetInstance(); + var processStepRepository = dimRepositories.GetInstance>(); processStepRepository.CreateProcessStep(ProcessStepTypeId.DELETE_TECHNICAL_USER, ProcessStepStatusId.TODO, processId); dimRepositories.GetInstance().AttachAndModifyTechnicalUser(technicalUserId, @@ -210,7 +212,7 @@ public async Task RetriggerProcess(ProcessTypeId processTypeId, Guid processId, { var stepToTrigger = processStepTypeId.GetStepForRetrigger(processTypeId); - var (validProcessId, processData) = await dimRepositories.GetInstance().IsValidProcess(processId, processTypeId, Enumerable.Repeat(processStepTypeId, 1)).ConfigureAwait(ConfigureAwaitOptions.None); + var (validProcessId, processData) = await dimRepositories.GetInstance>().IsValidProcess(processId, processTypeId, Enumerable.Repeat(processStepTypeId, 1)).ConfigureAwait(ConfigureAwaitOptions.None); if (!validProcessId) { throw new NotFoundException($"process {processId} does not exist"); diff --git a/src/web/Dim.Web/Dim.Web.csproj b/src/web/Dim.Web/Dim.Web.csproj index f11b81a..92de96c 100644 --- a/src/web/Dim.Web/Dim.Web.csproj +++ b/src/web/Dim.Web/Dim.Web.csproj @@ -14,14 +14,13 @@ - + - diff --git a/tests/database/Dim.DbAccess.Tests/Dim.DbAccess.Tests.csproj b/tests/database/Dim.DbAccess.Tests/Dim.DbAccess.Tests.csproj index 97d5f52..70763b1 100644 --- a/tests/database/Dim.DbAccess.Tests/Dim.DbAccess.Tests.csproj +++ b/tests/database/Dim.DbAccess.Tests/Dim.DbAccess.Tests.csproj @@ -32,7 +32,7 @@ - + diff --git a/tests/database/Dim.DbAccess.Tests/DimRepositoriesTests.cs b/tests/database/Dim.DbAccess.Tests/DimRepositoriesTests.cs index 49dacf1..aba877d 100644 --- a/tests/database/Dim.DbAccess.Tests/DimRepositoriesTests.cs +++ b/tests/database/Dim.DbAccess.Tests/DimRepositoriesTests.cs @@ -27,6 +27,7 @@ using Dim.Entities.Enums; using FluentAssertions; using Microsoft.EntityFrameworkCore; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.DBAccess; using Xunit; using Xunit.Extensions.AssemblyFixture; @@ -63,19 +64,6 @@ public async Task GetInstance_TechnicalUserRepository_CreatesSuccessfully() result.Should().BeOfType(); } - [Fact] - public async Task GetInstance_ProcessStepRepository_CreatesSuccessfully() - { - // Arrange - var sut = await CreateSut(); - - // Act - var result = sut.GetInstance(); - - // Assert - result.Should().BeOfType(); - } - #endregion #region Clear diff --git a/tests/database/Dim.DbAccess.Tests/ProcessStepRepositoryTests.cs b/tests/database/Dim.DbAccess.Tests/ProcessStepRepositoryTests.cs deleted file mode 100644 index 0c43dd9..0000000 --- a/tests/database/Dim.DbAccess.Tests/ProcessStepRepositoryTests.cs +++ /dev/null @@ -1,376 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2024 Contributors to the Eclipse Foundation - * - * 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 AutoFixture; -using AutoFixture.AutoFakeItEasy; -using Dim.DbAccess.Repositories; -using Dim.DbAccess.Tests.Setup; -using Dim.Entities; -using Dim.Entities.Entities; -using Dim.Entities.Enums; -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using System.Collections.Immutable; -using Xunit; -using Xunit.Extensions.AssemblyFixture; - -namespace Dim.DbAccess.Tests; - -public class ProcessStepRepositoryTests : IAssemblyFixture -{ - private readonly IFixture _fixture; - private readonly TestDbFixture _dbTestDbFixture; - - public ProcessStepRepositoryTests(TestDbFixture testDbFixture) - { - _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); - _fixture.Behaviors.OfType().ToList() - .ForEach(b => _fixture.Behaviors.Remove(b)); - - _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); - _dbTestDbFixture = testDbFixture; - } - - #region CreateProcess - - [Fact] - public async Task CreateProcess_CreatesSuccessfully() - { - // Arrange - var (sut, dbContext) = await CreateSutWithContext(); - var changeTracker = dbContext.ChangeTracker; - - // Act - var result = sut.CreateProcess(ProcessTypeId.SETUP_DIM); - - // Assert - changeTracker.HasChanges().Should().BeTrue(); - changeTracker.Entries().Should().HaveCount(1) - .And.AllSatisfy(x => - { - x.State.Should().Be(EntityState.Added); - x.Entity.Should().BeOfType(); - }); - changeTracker.Entries().Select(x => x.Entity).Cast() - .Should().Satisfy( - x => x.Id == result.Id && x.ProcessTypeId == ProcessTypeId.SETUP_DIM - ); - } - - #endregion - - #region CreateProcessStepRange - - [Fact] - public async Task CreateProcessStepRange_CreateSuccessfully() - { - // Arrange - var processId = Guid.NewGuid(); - var processStepTypeIds = _fixture.CreateMany(3).ToImmutableArray(); - var (sut, dbContext) = await CreateSutWithContext(); - var changeTracker = dbContext.ChangeTracker; - - // Act - var result = sut.CreateProcessStepRange(processStepTypeIds.Select(processStepTypeId => (processStepTypeId, ProcessStepStatusId.TODO, processId))); - - // Assert - changeTracker.HasChanges().Should().BeTrue(); - changeTracker.Entries().Should() - .HaveSameCount(processStepTypeIds) - .And.AllSatisfy(x => - { - x.State.Should().Be(EntityState.Added); - x.Entity.Should().BeOfType(); - }); - changeTracker.Entries().Select(x => x.Entity).Cast() - .Should().Satisfy( - x => x.Id == result.ElementAt(0).Id && x.ProcessId == processId && x.ProcessStepTypeId == processStepTypeIds[0] && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.Id == result.ElementAt(1).Id && x.ProcessId == processId && x.ProcessStepTypeId == processStepTypeIds[1] && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.Id == result.ElementAt(2).Id && x.ProcessId == processId && x.ProcessStepTypeId == processStepTypeIds[2] && x.ProcessStepStatusId == ProcessStepStatusId.TODO - ); - } - - #endregion - - #region CreateProcessStep - - [Fact] - public async Task CreateProcessStep_CreateSuccessfully() - { - // Arrange - var processId = Guid.NewGuid(); - var (sut, dbContext) = await CreateSutWithContext(); - var changeTracker = dbContext.ChangeTracker; - - // Act - sut.CreateProcessStep(ProcessStepTypeId.CREATE_WALLET, ProcessStepStatusId.TODO, processId); - - // Assert - changeTracker.HasChanges().Should().BeTrue(); - changeTracker.Entries().Should() - .ContainSingle() - .Which.State.Should().Be(EntityState.Added); - changeTracker.Entries().Select(x => x.Entity).Cast() - .Should().Satisfy( - x => x.ProcessId == processId && x.ProcessStepTypeId == ProcessStepTypeId.CREATE_WALLET && x.ProcessStepStatusId == ProcessStepStatusId.TODO - ); - } - - #endregion - - #region AttachAndModifyProcessStep - - [Fact] - public async Task AttachAndModifyProcessStep_WithExistingProcessStep_UpdatesStatus() - { - // Arrange - var (sut, dbContext) = await CreateSutWithContext(); - - // Act - sut.AttachAndModifyProcessStep(new Guid("48f35f84-8d98-4fbd-ba80-8cbce5eeadb5"), - existing => - { - existing.ProcessStepStatusId = ProcessStepStatusId.TODO; - }, - modify => - { - modify.ProcessStepStatusId = ProcessStepStatusId.DONE; - } - ); - - // Assert - var changeTracker = dbContext.ChangeTracker; - var changedEntries = changeTracker.Entries().ToList(); - changeTracker.HasChanges().Should().BeTrue(); - changedEntries.Should().NotBeEmpty(); - changedEntries.Should().HaveCount(1); - var changedEntity = changedEntries.Single(); - changedEntity.State.Should().Be(EntityState.Modified); - changedEntity.Entity.Should().BeOfType().Which.ProcessStepStatusId.Should().Be(ProcessStepStatusId.DONE); - } - - #endregion - - #region AttachAndModifyProcessSteps - - [Fact] - public async Task AttachAndModifyProcessSteps_UpdatesStatus() - { - // Arrange - var stepData = _fixture.CreateMany<(Guid ProcessStepId, ProcessStep InitialStep, ProcessStep ModifiedStep)>(5).ToImmutableArray(); - - var (sut, dbContext) = await CreateSutWithContext(); - - // Act - sut.AttachAndModifyProcessSteps(stepData.Select(data => new ValueTuple?, Action>( - data.ProcessStepId, - step => - { - step.ProcessStepStatusId = data.InitialStep.ProcessStepStatusId; - step.DateLastChanged = data.InitialStep.DateLastChanged; - step.Message = data.InitialStep.Message; - }, - step => - { - step.ProcessStepStatusId = data.ModifiedStep.ProcessStepStatusId; - step.DateLastChanged = data.ModifiedStep.DateLastChanged; - step.Message = data.ModifiedStep.Message; - }))); - - // Assert - var changeTracker = dbContext.ChangeTracker; - var changedEntries = changeTracker.Entries().ToList(); - changeTracker.HasChanges().Should().BeTrue(); - changedEntries.Should().HaveCount(5).And.AllSatisfy(entry => entry.State.Should().Be(EntityState.Modified)); - changedEntries.Select(entry => entry.Entity).Should().AllBeOfType().Which.Should().Satisfy( - step => step.Id == stepData[0].ProcessStepId && step.ProcessStepStatusId == stepData[0].ModifiedStep.ProcessStepStatusId && step.DateLastChanged == stepData[0].ModifiedStep.DateLastChanged && step.Message == stepData[0].ModifiedStep.Message, - step => step.Id == stepData[1].ProcessStepId && step.ProcessStepStatusId == stepData[1].ModifiedStep.ProcessStepStatusId && step.DateLastChanged == stepData[1].ModifiedStep.DateLastChanged && step.Message == stepData[1].ModifiedStep.Message, - step => step.Id == stepData[2].ProcessStepId && step.ProcessStepStatusId == stepData[2].ModifiedStep.ProcessStepStatusId && step.DateLastChanged == stepData[2].ModifiedStep.DateLastChanged && step.Message == stepData[2].ModifiedStep.Message, - step => step.Id == stepData[3].ProcessStepId && step.ProcessStepStatusId == stepData[3].ModifiedStep.ProcessStepStatusId && step.DateLastChanged == stepData[3].ModifiedStep.DateLastChanged && step.Message == stepData[3].ModifiedStep.Message, - step => step.Id == stepData[4].ProcessStepId && step.ProcessStepStatusId == stepData[4].ModifiedStep.ProcessStepStatusId && step.DateLastChanged == stepData[4].ModifiedStep.DateLastChanged && step.Message == stepData[4].ModifiedStep.Message - ); - } - - [Fact] - public async Task AttachAndModifyProcessSteps_WithUnmodifiedData_SkipsUpdateStatus() - { - // Arrange - var stepData = _fixture.CreateMany<(Guid ProcessStepId, ProcessStep InitialStep)>(5).ToImmutableArray(); - - var (sut, dbContext) = await CreateSutWithContext(); - - // Act - sut.AttachAndModifyProcessSteps(stepData.Select(data => new ValueTuple?, Action>( - data.ProcessStepId, - step => - { - step.ProcessStepStatusId = data.InitialStep.ProcessStepStatusId; - step.DateLastChanged = data.InitialStep.DateLastChanged; - step.Message = data.InitialStep.Message; - }, - step => - { - step.DateLastChanged = data.InitialStep.DateLastChanged; - }))); - - // Assert - var changeTracker = dbContext.ChangeTracker; - var changedEntries = changeTracker.Entries().ToList(); - changeTracker.HasChanges().Should().BeFalse(); - changedEntries.Should().HaveCount(5).And.AllSatisfy(entry => entry.State.Should().Be(EntityState.Unchanged)); - changedEntries.Select(entry => entry.Entity).Should().AllBeOfType().Which.Should().Satisfy( - step => step.Id == stepData[0].ProcessStepId && step.ProcessStepStatusId == stepData[0].InitialStep.ProcessStepStatusId && step.DateLastChanged == stepData[0].InitialStep.DateLastChanged && step.Message == stepData[0].InitialStep.Message, - step => step.Id == stepData[1].ProcessStepId && step.ProcessStepStatusId == stepData[1].InitialStep.ProcessStepStatusId && step.DateLastChanged == stepData[1].InitialStep.DateLastChanged && step.Message == stepData[1].InitialStep.Message, - step => step.Id == stepData[2].ProcessStepId && step.ProcessStepStatusId == stepData[2].InitialStep.ProcessStepStatusId && step.DateLastChanged == stepData[2].InitialStep.DateLastChanged && step.Message == stepData[2].InitialStep.Message, - step => step.Id == stepData[3].ProcessStepId && step.ProcessStepStatusId == stepData[3].InitialStep.ProcessStepStatusId && step.DateLastChanged == stepData[3].InitialStep.DateLastChanged && step.Message == stepData[3].InitialStep.Message, - step => step.Id == stepData[4].ProcessStepId && step.ProcessStepStatusId == stepData[4].InitialStep.ProcessStepStatusId && step.DateLastChanged == stepData[4].InitialStep.DateLastChanged && step.Message == stepData[4].InitialStep.Message - ); - } - - [Fact] - public async Task AttachAndModifyProcessSteps_WithUnmodifiedData_UpdatesLastChanged() - { - // Arrange - var stepData = _fixture.CreateMany<(Guid ProcessStepId, ProcessStep InitialStep)>(5).ToImmutableArray(); - - var (sut, dbContext) = await CreateSutWithContext(); - - // Act - sut.AttachAndModifyProcessSteps(stepData.Select(data => new ValueTuple?, Action>( - data.ProcessStepId, - step => - { - step.ProcessStepStatusId = data.InitialStep.ProcessStepStatusId; - step.DateLastChanged = data.InitialStep.DateLastChanged; - step.Message = data.InitialStep.Message; - }, - _ => { }))); - - // Assert - var changeTracker = dbContext.ChangeTracker; - var changedEntries = changeTracker.Entries().ToList(); - changeTracker.HasChanges().Should().BeTrue(); - changedEntries.Should().HaveCount(5).And.AllSatisfy(entry => entry.State.Should().Be(EntityState.Modified)); - changedEntries.Select(entry => entry.Entity).Should().AllBeOfType().Which.Should().Satisfy( - step => step.Id == stepData[0].ProcessStepId && step.ProcessStepStatusId == stepData[0].InitialStep.ProcessStepStatusId && step.DateLastChanged != stepData[0].InitialStep.DateLastChanged && step.Message == stepData[0].InitialStep.Message, - step => step.Id == stepData[1].ProcessStepId && step.ProcessStepStatusId == stepData[1].InitialStep.ProcessStepStatusId && step.DateLastChanged != stepData[1].InitialStep.DateLastChanged && step.Message == stepData[1].InitialStep.Message, - step => step.Id == stepData[2].ProcessStepId && step.ProcessStepStatusId == stepData[2].InitialStep.ProcessStepStatusId && step.DateLastChanged != stepData[2].InitialStep.DateLastChanged && step.Message == stepData[2].InitialStep.Message, - step => step.Id == stepData[3].ProcessStepId && step.ProcessStepStatusId == stepData[3].InitialStep.ProcessStepStatusId && step.DateLastChanged != stepData[3].InitialStep.DateLastChanged && step.Message == stepData[3].InitialStep.Message, - step => step.Id == stepData[4].ProcessStepId && step.ProcessStepStatusId == stepData[4].InitialStep.ProcessStepStatusId && step.DateLastChanged != stepData[4].InitialStep.DateLastChanged && step.Message == stepData[4].InitialStep.Message - ); - } - - #endregion - - #region GetActiveProcesses - - [Fact] - public async Task GetActiveProcess_LockExpired_ReturnsExpected() - { - // Arrange - var processTypeIds = new[] { ProcessTypeId.SETUP_DIM }; - var processStepTypeIds = new[] { - ProcessStepTypeId.CREATE_WALLET, - ProcessStepTypeId.CHECK_OPERATION, - ProcessStepTypeId.GET_COMPANY, - ProcessStepTypeId.GET_DID_DOCUMENT - }; - - var sut = await CreateSut(); - - // Act - var result = await sut.GetActiveProcesses(processTypeIds, processStepTypeIds, DateTimeOffset.UtcNow).ToListAsync(); - result.Should().HaveCount(2) - .And.Satisfy( - x => x.Id == new Guid("dd371565-9489-4907-a2e4-b8cbfe7a8cd1") && x.ProcessTypeId == ProcessTypeId.SETUP_DIM, - x => x.Id == new Guid("dd371565-9489-4907-a2e4-b8cbfe7a8cd2") && x.ProcessTypeId == ProcessTypeId.SETUP_DIM - ); - } - - [Fact] - public async Task GetActiveProcess_Locked_ReturnsExpected() - { - // Arrange - var processTypeIds = new[] { ProcessTypeId.SETUP_DIM }; - var processStepTypeIds = new[] { - ProcessStepTypeId.CREATE_WALLET, - ProcessStepTypeId.CHECK_OPERATION, - ProcessStepTypeId.GET_COMPANY, - ProcessStepTypeId.GET_DID_DOCUMENT - }; - - var sut = await CreateSut(); - - // Act - var result = await sut.GetActiveProcesses(processTypeIds, processStepTypeIds, DateTimeOffset.UtcNow).ToListAsync(); - result.Should().HaveCount(2); - } - - #endregion - - #region GetProcessStepData - - [Fact] - public async Task GetProcessStepData_ReturnsExpected() - { - // Arrange - var processId = new Guid("dd371565-9489-4907-a2e4-b8cbfe7a8cd2"); - var sut = await CreateSut(); - - // Act - var result = await sut.GetProcessStepData(processId).ToListAsync(); - result.Should().HaveCount(2) - .And.Satisfy( - x => x.ProcessStepId == new Guid("80771e4a-0d69-43b8-b278-25884da7f97d") && x.ProcessStepTypeId == ProcessStepTypeId.CREATE_WALLET, - x => x.ProcessStepId == new Guid("cd231cb8-55de-4ae4-b93f-d440512341fb") && x.ProcessStepTypeId == ProcessStepTypeId.GET_COMPANY - ); - } - - #endregion - - #region GetActiveProcesses - - [Fact] - public async Task IsValidProcess_WithValid_ReturnsExpected() - { - // Arrange - var sut = await CreateSut(); - - // Act - var result = await sut.IsValidProcess(new Guid("dd371565-9489-4907-a2e4-b8cbfe7a8cd1"), ProcessTypeId.SETUP_DIM, Enumerable.Repeat(ProcessStepTypeId.CREATE_WALLET, 1)); - - // Assert - result.ProcessExists.Should().BeTrue(); - } - - #endregion - - private async Task<(ProcessStepRepository sut, DimDbContext dbContext)> CreateSutWithContext() - { - var context = await _dbTestDbFixture.GetDbContext(); - var sut = new ProcessStepRepository(context); - return (sut, context); - } - - private async Task CreateSut() - { - var context = await _dbTestDbFixture.GetDbContext(); - return new ProcessStepRepository(context); - } -} diff --git a/tests/processes/DimProcess.Executor.Tests/DimProcessTypeExecutorTests.cs b/tests/processes/DimProcess.Executor.Tests/DimProcessTypeExecutorTests.cs index 4e59f7a..68b91c6 100644 --- a/tests/processes/DimProcess.Executor.Tests/DimProcessTypeExecutorTests.cs +++ b/tests/processes/DimProcess.Executor.Tests/DimProcessTypeExecutorTests.cs @@ -23,6 +23,7 @@ using Dim.Entities.Enums; using DimProcess.Library; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; namespace DimProcess.Executor.Tests; diff --git a/tests/processes/DimProcess.Executor.Tests/TechnicalUserProcessTypeExecutorTests.cs b/tests/processes/DimProcess.Executor.Tests/TechnicalUserProcessTypeExecutorTests.cs index c57bfc6..534c30f 100644 --- a/tests/processes/DimProcess.Executor.Tests/TechnicalUserProcessTypeExecutorTests.cs +++ b/tests/processes/DimProcess.Executor.Tests/TechnicalUserProcessTypeExecutorTests.cs @@ -23,6 +23,7 @@ using Dim.Entities.Enums; using DimProcess.Library; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; namespace DimProcess.Executor.Tests; diff --git a/tests/processes/DimProcess.Library.Tests/DimProcessHandlerTests.cs b/tests/processes/DimProcess.Library.Tests/DimProcessHandlerTests.cs index 7f8e240..b49c386 100644 --- a/tests/processes/DimProcess.Library.Tests/DimProcessHandlerTests.cs +++ b/tests/processes/DimProcess.Library.Tests/DimProcessHandlerTests.cs @@ -33,6 +33,7 @@ using Microsoft.Extensions.Options; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; using System.Net; using System.Security.Cryptography; using System.Text.Json; diff --git a/tests/processes/DimProcess.Library.Tests/TechnicalUserProcessHandlerTests.cs b/tests/processes/DimProcess.Library.Tests/TechnicalUserProcessHandlerTests.cs index 26d2660..57ed2e6 100644 --- a/tests/processes/DimProcess.Library.Tests/TechnicalUserProcessHandlerTests.cs +++ b/tests/processes/DimProcess.Library.Tests/TechnicalUserProcessHandlerTests.cs @@ -31,6 +31,7 @@ using Microsoft.Extensions.Options; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; using System.Security.Cryptography; namespace DimProcess.Library.Tests; diff --git a/tests/processes/Processes.Library.Tests/ManualProcessDataExtensionsTests.cs b/tests/processes/Processes.Library.Tests/ManualProcessDataExtensionsTests.cs deleted file mode 100644 index f0c213e..0000000 --- a/tests/processes/Processes.Library.Tests/ManualProcessDataExtensionsTests.cs +++ /dev/null @@ -1,517 +0,0 @@ -/******************************************************************************** - * 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.DbAccess; -using Dim.DbAccess.Models; -using Dim.DbAccess.Repositories; -using Dim.Entities.Entities; -using Dim.Entities.Enums; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; -using System.Collections.Immutable; -using ProcessStepTypeId = Dim.Entities.Enums.ProcessStepTypeId; -using ProcessTypeId = Dim.Entities.Enums.ProcessTypeId; - -namespace Dim.Processes.Library.Tests; - -public class ManualProcessDataExtensionsTests -{ - private readonly IDimRepositories _respositories; - private readonly IProcessStepRepository _processStepRepository; - private readonly string _entityName; - private readonly Func _getProcessEntityName; - private readonly IFixture _fixture; - - public ManualProcessDataExtensionsTests() - { - _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); - _fixture.Behaviors.OfType().ToList() - .ForEach(b => _fixture.Behaviors.Remove(b)); - _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); - - _respositories = A.Fake(); - _processStepRepository = A.Fake(); - - A.CallTo(() => _respositories.GetInstance()) - .Returns(_processStepRepository); - - _entityName = _fixture.Create(); - _getProcessEntityName = () => _entityName; - } - - #region CreateManualProcessData - - [Fact] - public void CreateManualProcessData_ReturnsExpected() - { - // Arrange - var process = new Process(Guid.NewGuid(), _fixture.Create(), Guid.NewGuid()) { LockExpiryDate = null }; - var processSteps = _fixture.CreateMany<(Guid ProcessStepId, DateTimeOffset Now)>(5).Select(x => new ProcessStep(x.ProcessStepId, _fixture.Create(), Entities.Enums.ProcessStepStatusId.TODO, process.Id, x.Now)).ToImmutableArray(); - var stepTypeId = processSteps[2].ProcessStepTypeId; - - var sut = _fixture.Build() - .With(x => x.Process, process) - .With(x => x.ProcessSteps, processSteps) - .Create(); - - // Act - var result = sut.CreateManualProcessData(stepTypeId, _respositories, _getProcessEntityName); - - // Assert - result.Should().NotBeNull().And.BeOfType().And.Match( - data => - data.ProcessStepTypeId == stepTypeId && - data.Process == sut.Process && - data.ProcessSteps.SequenceEqual(sut.ProcessSteps!) && - data.PortalRepositories == _respositories); - } - - [Fact] - public void CreateManualProcessData_WithNullVerifyProcessData_Throws() - { - // Arrange - var sut = (VerifyProcessData?)null; - - var Act = () => sut.CreateManualProcessData(_fixture.Create(), _respositories, _getProcessEntityName); - - // Act - var result = Assert.Throws(Act); - - // Assert - result.Message.Should().Be($"{_entityName} does not exist"); - } - - [Fact] - public void CreateManualProcessData_WithNullProcess_Throws() - { - // Arrange - var sut = _fixture.Build() - .With(x => x.Process, (Process?)null) - .Create(); - - var Act = () => sut.CreateManualProcessData(_fixture.Create(), _respositories, _getProcessEntityName); - - // Act - var result = Assert.Throws(Act); - - // Assert - result.Message.Should().Be($"{_entityName} is not associated with any process"); - } - - [Fact] - public void CreateManualProcessData_WithLockedProcess_Throws() - { - // Arrange - var expiryDate = _fixture.Create(); - var process = new Process(Guid.NewGuid(), _fixture.Create(), Guid.NewGuid()) { LockExpiryDate = expiryDate }; - var sut = _fixture.Build() - .With(x => x.Process, process) - .Create(); - - var Act = () => sut.CreateManualProcessData(_fixture.Create(), _respositories, _getProcessEntityName); - - // Act - var result = Assert.Throws(Act); - - // Assert - result.Message.Should().Be($"process {process.Id} associated with {_entityName} is locked, lock expiry is set to {expiryDate}"); - } - - [Fact] - public void CreateManualProcessData_WithNullProcessSteps_Throws() - { - // Arrange - var process = new Process(Guid.NewGuid(), _fixture.Create(), Guid.NewGuid()) { LockExpiryDate = null }; - var processSteps = _fixture.CreateMany<(Guid ProcessStepId, DateTimeOffset Now)>(5).Select(x => new ProcessStep(x.ProcessStepId, _fixture.Create(), Entities.Enums.ProcessStepStatusId.TODO, process.Id, x.Now)).ToImmutableArray(); - - var sut = _fixture.Build() - .With(x => x.Process, process) - .With(x => x.ProcessSteps, (IEnumerable?)null) - .Create(); - - var Act = () => sut.CreateManualProcessData(_fixture.Create(), _respositories, _getProcessEntityName); - - // Act - var result = Assert.Throws(Act); - - // Assert - result.Message.Should().Be("processSteps should never be null here"); - } - - [Fact] - public void CreateManualProcessData_WithInvalidProcessStepStatus_Throws() - { - // Arrange - var process = new Process(Guid.NewGuid(), _fixture.Create(), Guid.NewGuid()) { LockExpiryDate = null }; - var processSteps = _fixture.CreateMany<(Guid ProcessStepId, DateTimeOffset Now)>(5).Select(x => new ProcessStep(x.ProcessStepId, _fixture.Create(), Entities.Enums.ProcessStepStatusId.DONE, process.Id, x.Now)).ToImmutableArray(); - - var sut = _fixture.Build() - .With(x => x.Process, process) - .With(x => x.ProcessSteps, processSteps) - .Create(); - - var Act = () => sut.CreateManualProcessData(_fixture.Create(), _respositories, _getProcessEntityName); - - // Act - var result = Assert.Throws(Act); - - // Assert - result.Message.Should().Be("processSteps should never have any other status than TODO here"); - } - - [Fact] - public void CreateManualProcessData_WithInvalidProcessStepType_Throws() - { - // Arrange - var process = new Process(Guid.NewGuid(), _fixture.Create(), Guid.NewGuid()) { LockExpiryDate = null }; - var processSteps = _fixture.CreateMany<(Guid ProcessStepId, DateTimeOffset Now)>(5).Select(x => new ProcessStep(x.ProcessStepId, _fixture.Create(), Entities.Enums.ProcessStepStatusId.TODO, process.Id, x.Now)).ToImmutableArray(); - var stepTypeId = Enum.GetValues().Except(processSteps.Select(step => step.ProcessStepTypeId)).First(); - - var sut = _fixture.Build() - .With(x => x.Process, process) - .With(x => x.ProcessSteps, processSteps) - .Create(); - - var Act = () => sut.CreateManualProcessData(stepTypeId, _respositories, _getProcessEntityName); - - // Act - var result = Assert.Throws(Act); - - // Assert - result.Message.Should().Be($"{_entityName}, process step {stepTypeId} is not eligible to run"); - } - - #endregion - - #region RequestLock - - [Fact] - public void RequestLock_WithUnLockedProcess_ReturnsExpected() - { - // Arrange - var expiryDate = _fixture.Create(); - var process = new Process(Guid.NewGuid(), _fixture.Create(), Guid.NewGuid()) { LockExpiryDate = null }; - var sut = _fixture.Build() - .With(x => x.Process, process) - .With(x => x.PortalRepositories, _respositories) - .Create(); - - // Act - sut.RequestLock(expiryDate); - - // Assert - sut.Process.LockExpiryDate.Should().Be(expiryDate); - A.CallTo(() => _respositories.Attach(process, null)).MustHaveHappenedOnceExactly(); - } - - [Fact] - public void RequestLock_WithLockedProcess_Throws() - { - // Arrange - var expiryDate = _fixture.Create(); - var process = new Process(Guid.NewGuid(), _fixture.Create(), Guid.NewGuid()) { LockExpiryDate = expiryDate }; - var sut = _fixture.Build() - .With(x => x.Process, process) - .With(x => x.PortalRepositories, _respositories) - .Create(); - - var Act = () => sut.RequestLock(DateTimeOffset.UtcNow); - // Act - var result = Assert.Throws(Act); - - // Assert - result.Message.Should().Be("process TryLock should never fail here"); - sut.Process.LockExpiryDate.Should().Be(expiryDate); - A.CallTo(() => _respositories.Attach(process, null)).MustHaveHappenedOnceExactly(); - } - - #endregion - - #region SkipProcessSteps - - [Fact] - public void SkipProcessSteps_ReturnsExpected() - { - // Arrange - var process = _fixture.Create(); - var stepTypeIds = _fixture.CreateMany(4).ToImmutableArray(); - var before = DateTimeOffset.UtcNow.AddDays(-1); - var processSteps0 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[0], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[0], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[0], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - var processSteps1 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[1], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[1], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[1], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - var processSteps2 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[2], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[2], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[2], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - var processSteps3 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[3], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[3], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[3], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - - var processSteps = new[] - { - processSteps0[0], - processSteps1[0], - processSteps2[0], - processSteps3[0], - processSteps0[1], - processSteps1[1], - processSteps2[1], - processSteps3[1], - processSteps0[2], - processSteps1[2], - processSteps2[2], - processSteps3[2], - }; - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A?, Action)>>._)) - .Invokes((IEnumerable<(Guid ProcessStepId, Action? Initialize, Action Modify)> processStepIdInitializeModify) => - { - foreach (var (stepId, initialize, modify) in processStepIdInitializeModify) - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - } - }); - - var sut = _fixture.Build() - .With(x => x.ProcessStepTypeId, stepTypeIds[3]) - .With(x => x.Process, process) - .With(x => x.PortalRepositories, _respositories) - .With(x => x.ProcessSteps, processSteps) - .Create(); - - // Act - sut.SkipProcessSteps(new ProcessStepTypeId[] { stepTypeIds[1], stepTypeIds[2], stepTypeIds[3] }); - - // Assert - A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A?, Action)>>._)) - .MustHaveHappenedOnceExactly(); - - modifiedProcessSteps.Should().HaveCount(6).And.Satisfy( - x => processSteps1.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.SKIPPED && x.DateLastChanged != before, - x => processSteps1.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.DUPLICATE && x.DateLastChanged != before, - x => processSteps1.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.DUPLICATE && x.DateLastChanged != before, - x => processSteps2.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.SKIPPED && x.DateLastChanged != before, - x => processSteps2.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.DUPLICATE && x.DateLastChanged != before, - x => processSteps2.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.DUPLICATE && x.DateLastChanged != before - ); - } - - #endregion - - #region SkipProcessStepsExcept - - [Fact] - public void SkipProcessStepsExcept_ReturnsExpected() - { - // Arrange - var process = _fixture.Create(); - var stepTypeIds = _fixture.CreateMany(4).ToImmutableArray(); - var before = DateTimeOffset.UtcNow.AddDays(-1); - var processSteps0 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[0], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[0], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[0], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - var processSteps1 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[1], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[1], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[1], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - var processSteps2 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[2], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[2], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[2], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - var processSteps3 = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[3], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[3], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[3], Entities.Enums.ProcessStepStatusId.TODO, process.Id, before) - }; - - var processSteps = new[] - { - processSteps0[0], - processSteps1[0], - processSteps2[0], - processSteps3[0], - processSteps0[1], - processSteps1[1], - processSteps2[1], - processSteps3[1], - processSteps0[2], - processSteps1[2], - processSteps2[2], - processSteps3[2], - }; - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A?, Action)>>._)) - .Invokes((IEnumerable<(Guid ProcessStepId, Action? Initialize, Action Modify)> processStepIdInitializeModify) => - { - foreach (var (stepId, initialize, modify) in processStepIdInitializeModify) - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - } - }); - - var sut = _fixture.Build() - .With(x => x.ProcessStepTypeId, stepTypeIds[3]) - .With(x => x.Process, process) - .With(x => x.PortalRepositories, _respositories) - .With(x => x.ProcessSteps, processSteps) - .Create(); - - // Act - sut.SkipProcessStepsExcept(new ProcessStepTypeId[] { stepTypeIds[1], stepTypeIds[2] }); - - // Assert - A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A?, Action)>>._)) - .MustHaveHappenedOnceExactly(); - - modifiedProcessSteps.Should().HaveCount(3).And.Satisfy( - x => processSteps0.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.SKIPPED && x.DateLastChanged != before, - x => processSteps0.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.DUPLICATE && x.DateLastChanged != before, - x => processSteps0.Any(step => step.Id == x.Id) && x.ProcessStepStatusId == Entities.Enums.ProcessStepStatusId.DUPLICATE && x.DateLastChanged != before - ); - } - - #endregion - - #region ScheduleProcessSteps - - [Fact] - public void ScheduleProcessSteps_ReturnsExpected() - { - // Arrange - var stepTypeIds = _fixture.CreateMany(3).ToImmutableArray(); - var now = DateTimeOffset.UtcNow; - - var createdSteps = new List(); - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcesssStepTypeId, Entities.Enums.ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatusProcessIds) => - { - foreach (var data in processStepTypeStatusProcessIds) - { - createdSteps.Add(new ProcessStep(Guid.NewGuid(), data.ProcesssStepTypeId, data.ProcessStepStatusId, data.ProcessId, now)); - } - return createdSteps; - }); - - var sut = _fixture.Build() - .With(x => x.PortalRepositories, _respositories) - .Create(); - - // Act - sut.ScheduleProcessSteps(stepTypeIds); - - // Assert - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustHaveHappenedOnceExactly(); - createdSteps.Should().HaveCount(3).And.Satisfy( - x => x.ProcessStepTypeId == stepTypeIds[0] && x.ProcessId == sut.Process.Id && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.ProcessStepTypeId == stepTypeIds[1] && x.ProcessId == sut.Process.Id && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.ProcessStepTypeId == stepTypeIds[2] && x.ProcessId == sut.Process.Id && x.ProcessStepStatusId == ProcessStepStatusId.TODO - ); - } - - #endregion - - #region FinalizeProcessStep - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void FinalizeProcessStep_ReturnsExpected(bool locked) - { - // Arrange - var version = Guid.NewGuid(); - var process = _fixture.Build() - .With(x => x.Version, version) - .With(x => x.LockExpiryDate, locked ? DateTimeOffset.UtcNow : (DateTimeOffset?)null) - .Create(); - var stepTypeIds = _fixture.CreateMany(3).ToImmutableArray(); - var before = DateTimeOffset.UtcNow.AddDays(-1); - var processSteps = new ProcessStep[] - { - new(Guid.NewGuid(), stepTypeIds[0], ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[1], ProcessStepStatusId.TODO, process.Id, before), - new(Guid.NewGuid(), stepTypeIds[2], ProcessStepStatusId.TODO, process.Id, before) - }; - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A?, Action)>>._)) - .Invokes((IEnumerable<(Guid ProcessStepId, Action? Initialize, Action Modify)> processStepIdInitializeModify) => - { - foreach (var (stepId, initialize, modify) in processStepIdInitializeModify) - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - } - }); - - var sut = new ManualProcessStepData(stepTypeIds[1], process, processSteps, _respositories); - - // Act - sut.FinalizeProcessStep(); - - // Assert - A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A?, Action)>>._)) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _respositories.Attach(process, null)) - .MustHaveHappenedOnceExactly(); - - process.LockExpiryDate.Should().BeNull(); - process.Version.Should().NotBe(version); - modifiedProcessSteps.Should().ContainSingle().Which.Should().Match( - x => x.Id == processSteps[1].Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE && x.DateLastChanged != before - ); - } - - #endregion -} diff --git a/tests/processes/Processes.Library.Tests/Processes.Library.Tests.csproj b/tests/processes/Processes.Library.Tests/Processes.Library.Tests.csproj deleted file mode 100644 index 6efc16c..0000000 --- a/tests/processes/Processes.Library.Tests/Processes.Library.Tests.csproj +++ /dev/null @@ -1,46 +0,0 @@ - - - - - net8.0 - enable - enable - false - Dim.Processes.Library.Tests - Dim.Processes.Library.Tests - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - diff --git a/tests/processes/Processes.Library.Tests/Usings.cs b/tests/processes/Processes.Library.Tests/Usings.cs deleted file mode 100644 index ded99ae..0000000 --- a/tests/processes/Processes.Library.Tests/Usings.cs +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************** - * 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; diff --git a/tests/processes/Processes.Worker.Library.Tests/ProcessExecutionServiceTests.cs b/tests/processes/Processes.Worker.Library.Tests/ProcessExecutionServiceTests.cs deleted file mode 100644 index d731e8e..0000000 --- a/tests/processes/Processes.Worker.Library.Tests/ProcessExecutionServiceTests.cs +++ /dev/null @@ -1,513 +0,0 @@ -/******************************************************************************** - * 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.DbAccess; -using Dim.DbAccess.Repositories; -using Dim.Entities.Entities; -using Dim.Entities.Enums; -using Dim.Tests.Shared; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider; -using System.Collections.Immutable; - -namespace Processes.Worker.Library.Tests; - -public class ProcessExecutionServiceTests -{ - private readonly IProcessStepRepository _processStepRepository; - private readonly IDimRepositories _repositories; - private readonly IProcessExecutor _processExecutor; - private readonly IMockLogger _mockLogger; - private readonly ProcessExecutionService _service; - private readonly IFixture _fixture; - - public ProcessExecutionServiceTests() - { - _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); - _fixture.Behaviors.OfType().ToList() - .ForEach(b => _fixture.Behaviors.Remove(b)); - _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); - - var dateTimeProvider = A.Fake(); - _repositories = A.Fake(); - _processStepRepository = A.Fake(); - _processExecutor = A.Fake(); - - _mockLogger = A.Fake>(); - ILogger logger = new MockLogger(_mockLogger); - - A.CallTo(() => _repositories.GetInstance()) - .Returns(_processStepRepository); - - var settings = _fixture.Create(); - - var options = Options.Create(settings); - var serviceProvider = A.Fake(); - A.CallTo(() => serviceProvider.GetService(typeof(IDimRepositories))).Returns(_repositories); - A.CallTo(() => serviceProvider.GetService(typeof(IProcessExecutor))).Returns(_processExecutor); - var serviceScope = A.Fake(); - A.CallTo(() => serviceScope.ServiceProvider).Returns(serviceProvider); - var serviceScopeFactory = A.Fake(); - A.CallTo(() => serviceScopeFactory.CreateScope()).Returns(serviceScope); - A.CallTo(() => serviceProvider.GetService(typeof(IServiceScopeFactory))).Returns(serviceScopeFactory); - - _service = new ProcessExecutionService(serviceScopeFactory, dateTimeProvider, options, logger); - } - - [Fact] - public async Task ExecuteAsync_WithNoPendingItems_NoServiceCall() - { - // Arrange - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(Array.Empty().ToAsyncEnumerable()); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustNotHaveHappened(); - } - - [Fact] - public async Task ExecuteAsync_WithPendingItems_CallsProcessExpectedNumberOfTimes() - { - // Arrange - var processData = _fixture.CreateMany().Select(x => new Process(x, ProcessTypeId.SETUP_DIM, Guid.NewGuid())).ToImmutableArray(); - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .Returns(Enumerable.Repeat(IProcessExecutor.ProcessExecutionResult.SaveRequested, 2).ToAsyncEnumerable()); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustHaveHappened(processData.Length, Times.Exactly); - A.CallTo(() => _repositories.SaveAsync()) - .MustHaveHappened(processData.Length * 2, Times.Exactly); - A.CallTo(() => _repositories.Clear()) - .MustHaveHappened(processData.Length * 2, Times.Exactly); - } - - [Fact] - public async Task ExecuteAsync_ExecuteProcess_Returns_Unmodified() - { - // Arrange - var processData = _fixture.CreateMany().Select(x => new Process(x, ProcessTypeId.SETUP_DIM, Guid.NewGuid())).ToImmutableArray(); - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .Returns(Enumerable.Repeat(IProcessExecutor.ProcessExecutionResult.Unmodified, 2).ToAsyncEnumerable()); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustHaveHappened(processData.Length, Times.Exactly); - A.CallTo(() => _repositories.SaveAsync()) - .MustNotHaveHappened(); - A.CallTo(() => _repositories.Clear()) - .MustHaveHappened(processData.Length * 2, Times.Exactly); - } - - [Fact] - public async Task ExecuteAsync_ExecuteProcess_Returns_RequestLock() - { - // Arrange - var processId = Guid.NewGuid(); - var processVersion = Guid.NewGuid(); - var process = new Process(processId, ProcessTypeId.SETUP_DIM, processVersion); - var processData = new[] { process }; - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - A.CallTo(() => _processExecutor.ExecuteProcess(processId, A._, A._)) - .Returns(new[] { IProcessExecutor.ProcessExecutionResult.LockRequested, IProcessExecutor.ProcessExecutionResult.SaveRequested }.ToAsyncEnumerable()); - - var changeHistory = new List<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(); - - A.CallTo(() => _repositories.SaveAsync()) - .ReturnsLazily(() => - { - changeHistory.Add((process.Version, process.LockExpiryDate, true)); - return 1; - }); - - A.CallTo(() => _repositories.Clear()) - .Invokes(() => - { - changeHistory.Add((process.Version, process.LockExpiryDate, false)); - }); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _repositories.SaveAsync()) - .MustHaveHappened(3, Times.Exactly); - A.CallTo(() => _repositories.Clear()) - .MustHaveHappened(3, Times.Exactly); - changeHistory.Should().HaveCount(6) - .And.SatisfyRespectively( - first => first.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version != processVersion && x.LockExpiryTime != null && x.Save), - second => second.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[0].Version && x.LockExpiryTime == changeHistory[0].LockExpiryTime && !x.Save), - third => third.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[1].Version && x.LockExpiryTime == changeHistory[1].LockExpiryTime && x.Save), - forth => forth.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[2].Version && x.LockExpiryTime == changeHistory[2].LockExpiryTime && !x.Save), - fifth => fifth.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version != changeHistory[3].Version && x.LockExpiryTime == null && x.Save), - sixth => sixth.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[4].Version && x.LockExpiryTime == null && !x.Save) - ); - } - - [Fact] - public async Task ExecuteAsync_ExecuteProcess_Returns_RequestLockTwice() - { - // Arrange - var processId = Guid.NewGuid(); - var processVersion = Guid.NewGuid(); - var process = new Process(processId, ProcessTypeId.SETUP_DIM, processVersion); - var processData = new[] { process }; - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - A.CallTo(() => _processExecutor.ExecuteProcess(processId, A._, A._)) - .Returns(new[] { IProcessExecutor.ProcessExecutionResult.LockRequested, IProcessExecutor.ProcessExecutionResult.LockRequested, IProcessExecutor.ProcessExecutionResult.SaveRequested }.ToAsyncEnumerable()); - - var changeHistory = new List<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(); - - A.CallTo(() => _repositories.SaveAsync()) - .ReturnsLazily(() => - { - changeHistory.Add((process.Version, process.LockExpiryDate, true)); - return 1; - }); - - A.CallTo(() => _repositories.Clear()) - .Invokes(() => - { - changeHistory.Add((process.Version, process.LockExpiryDate, false)); - }); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _repositories.SaveAsync()) - .MustHaveHappened(3, Times.Exactly); - A.CallTo(() => _repositories.Clear()) - .MustHaveHappened(4, Times.Exactly); - changeHistory.Should().HaveCount(7) - .And.SatisfyRespectively( - first => first.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version != processVersion && x.LockExpiryTime != null && x.Save), - second => second.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[0].Version && x.LockExpiryTime == changeHistory[0].LockExpiryTime && !x.Save), - third => third.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[1].Version && x.LockExpiryTime == changeHistory[1].LockExpiryTime && !x.Save), - forth => forth.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[2].Version && x.LockExpiryTime == changeHistory[2].LockExpiryTime && x.Save), - fifth => fifth.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[3].Version && x.LockExpiryTime == changeHistory[3].LockExpiryTime && !x.Save), - sixth => sixth.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version != changeHistory[4].Version && x.LockExpiryTime == null && x.Save), - seventh => seventh.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[5].Version && x.LockExpiryTime == null && !x.Save) - ); - } - - [Fact] - public async Task ExecuteAsync_ExecuteProcess_Returns_RequestLockThenThrows() - { - // Arrange - var firstId = Guid.NewGuid(); - var secondId = Guid.NewGuid(); - var firstVersion = Guid.NewGuid(); - var secondVersion = Guid.NewGuid(); - var firstProcess = new Process(firstId, ProcessTypeId.SETUP_DIM, firstVersion); - var secondProcess = new Process(secondId, ProcessTypeId.SETUP_DIM, secondVersion); - - var processData = new[] { firstProcess, secondProcess }; - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - IEnumerable ThrowingEnumerable() - { - yield return IProcessExecutor.ProcessExecutionResult.LockRequested; - throw new Exception("normal error"); - } - - Process? process = null; - - A.CallTo(() => _processExecutor.ExecuteProcess(firstId, A._, A._)) - .ReturnsLazily((Guid Id, ProcessTypeId _, CancellationToken _) => - { - process = firstProcess; - return ThrowingEnumerable().ToAsyncEnumerable(); - }); - - A.CallTo(() => _processExecutor.ExecuteProcess(secondId, A._, A._)) - .ReturnsLazily((Guid Id, ProcessTypeId _, CancellationToken _) => - { - process = secondProcess; - return new[] { IProcessExecutor.ProcessExecutionResult.SaveRequested }.ToAsyncEnumerable(); - }); - - var changeHistory = new List<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(); - - A.CallTo(() => _repositories.SaveAsync()) - .ReturnsLazily(() => - { - changeHistory.Add(process == null - ? (Guid.Empty, Guid.Empty, null, true) - : (process.Id, process.Version, process.LockExpiryDate, true)); - return 1; - }); - - A.CallTo(() => _repositories.Clear()) - .Invokes(() => - { - changeHistory.Add(process == null - ? (Guid.Empty, Guid.Empty, null, false) - : (process.Id, process.Version, process.LockExpiryDate, false)); - }); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(firstId, A._, A._)) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _processExecutor.ExecuteProcess(secondId, A._, A._)) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _repositories.SaveAsync()) - .MustHaveHappenedTwiceExactly(); - A.CallTo(() => _repositories.Clear()) - .MustHaveHappened(3, Times.Exactly); - changeHistory.Should().SatisfyRespectively( - first => first.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Id == firstId && x.Version != firstVersion && x.LockExpiryTime != null && x.Save), - second => second.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Id == firstId && x.Version == changeHistory[0].Version && x.LockExpiryTime == changeHistory[0].LockExpiryTime && !x.Save), - second => second.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Id == firstId && x.Version == changeHistory[1].Version && x.LockExpiryTime == changeHistory[0].LockExpiryTime && !x.Save), - third => third.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Id == secondId && x.Version != secondVersion && x.LockExpiryTime == null && x.Save), - forth => forth.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Id == secondId && x.Version == changeHistory[3].Version && x.LockExpiryTime == null && !x.Save) - ); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.Matches(e => e != null && e.Message == "normal error"), A.That.StartsWith("error processing process"))).MustHaveHappenedOnceExactly(); - } - - [Fact] - public async Task ExecuteAsync_ExecuteProcess_Returns_UnmodifiedSafeRequested() - { - // Arrange - var firstVersion = Guid.NewGuid(); - var process = new Process(Guid.NewGuid(), ProcessTypeId.SETUP_DIM, firstVersion); - var processData = new[] { process }; - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .Returns(new[] { IProcessExecutor.ProcessExecutionResult.Unmodified, IProcessExecutor.ProcessExecutionResult.SaveRequested }.ToAsyncEnumerable()); - - var changeHistory = new List<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(); - - A.CallTo(() => _repositories.SaveAsync()) - .ReturnsLazily(() => - { - changeHistory.Add((process.Version, process.LockExpiryDate, true)); - return 1; - }); - - A.CallTo(() => _repositories.Clear()) - .Invokes(() => - { - changeHistory.Add((process.Version, process.LockExpiryDate, false)); - }); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _repositories.SaveAsync()) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _repositories.Clear()) - .MustHaveHappenedTwiceExactly(); - changeHistory.Should().HaveCount(3) - .And.SatisfyRespectively( - first => first.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == firstVersion && x.LockExpiryTime == null && !x.Save), - second => second.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version != changeHistory[0].Version && x.LockExpiryTime == null && x.Save), - third => third.Should().Match<(Guid Version, DateTimeOffset? LockExpiryTime, bool Save)>(x => x.Version == changeHistory[1].Version && x.LockExpiryTime == null && !x.Save) - ); - } - - [Fact] - public async Task ExecuteAsync_ExecuteProcess_Returns_RequestLock_SaveAsyncThrows() - { - // Arrange - var firstProcessId = Guid.NewGuid(); - var firstVersion = Guid.NewGuid(); - var firstProcess = new Process(firstProcessId, ProcessTypeId.SETUP_DIM, firstVersion); - var secondProcessId = Guid.NewGuid(); - var secondVersion = Guid.NewGuid(); - var secondProcess = new Process(secondProcessId, ProcessTypeId.SETUP_DIM, secondVersion); - var thirdProcessId = Guid.NewGuid(); - var thirdVersion = Guid.NewGuid(); - var thirdProcess = new Process(thirdProcessId, ProcessTypeId.SETUP_DIM, thirdVersion); - var processData = new[] { firstProcess, secondProcess, thirdProcess }; - var error = new Exception("save conflict error"); - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - Process? process = null; - - A.CallTo(() => _processExecutor.ExecuteProcess(firstProcessId, A._, A._)) - .ReturnsLazily((Guid _, ProcessTypeId _, CancellationToken _) => - { - process = firstProcess; - return new[] { IProcessExecutor.ProcessExecutionResult.LockRequested, IProcessExecutor.ProcessExecutionResult.SaveRequested }.ToAsyncEnumerable(); - }); - - A.CallTo(() => _processExecutor.ExecuteProcess(secondProcessId, A._, A._)) - .ReturnsLazily((Guid _, ProcessTypeId _, CancellationToken _) => - { - process = secondProcess; - return new[] { IProcessExecutor.ProcessExecutionResult.SaveRequested }.ToAsyncEnumerable(); - }); - - A.CallTo(() => _processExecutor.ExecuteProcess(thirdProcessId, A._, A._)) - .ReturnsLazily((Guid _, ProcessTypeId _, CancellationToken _) => - { - process = thirdProcess; - return new[] { IProcessExecutor.ProcessExecutionResult.Unmodified }.ToAsyncEnumerable(); - }); - - var changeHistory = new List<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime)>(); - - A.CallTo(() => _repositories.SaveAsync()) - .Throws(error); - - A.CallTo(() => _repositories.Clear()) - .Invokes(() => - { - changeHistory.Add( - process == null - ? (Guid.Empty, Guid.Empty, null) - : (process.Id, process.Version, process.LockExpiryDate)); - }); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustHaveHappened(3, Times.Exactly); - A.CallTo(() => _repositories.SaveAsync()) - .MustHaveHappenedTwiceExactly(); - A.CallTo(() => _repositories.Clear()) - .MustHaveHappened(3, Times.Exactly); - changeHistory.Should().HaveCount(3) - .And.SatisfyRespectively( - first => first.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime)>(x => x.Id == firstProcessId && x.Version != firstVersion && x.LockExpiryTime != null), - second => second.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime)>(x => x.Id == secondProcessId && x.Version != secondVersion && x.LockExpiryTime == null), - third => third.Should().Match<(Guid Id, Guid Version, DateTimeOffset? LockExpiryTime)>(x => x.Id == thirdProcessId && x.Version == thirdVersion && x.LockExpiryTime == null) - ); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.Matches(e => e != null && e.Message == error.Message), A.That.StartsWith($"error processing process {firstProcessId}"))) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.Matches(e => e != null && e.Message == error.Message), A.That.StartsWith($"error processing process {secondProcessId}"))) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.Matches(e => e != null && e.Message == error.Message), A.That.StartsWith($"error processing process {thirdProcessId}"))) - .MustNotHaveHappened(); - } - - [Fact] - public async Task ExecuteAsync_IgnoresLockedProcesses_LogsInformation() - { - var lockExpiryDate = _fixture.Create(); - // Arrange - var processData = _fixture.CreateMany().Select(x => new Process(x, ProcessTypeId.SETUP_DIM, Guid.NewGuid()) { LockExpiryDate = lockExpiryDate }).ToImmutableArray(); - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.IsNull(), A.That.StartsWith("skipping locked process"))) - .MustHaveHappened(processData.Length, Times.Exactly); - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .MustNotHaveHappened(); - A.CallTo(() => _repositories.SaveAsync()) - .MustNotHaveHappened(); - A.CallTo(() => _repositories.Clear()) - .MustNotHaveHappened(); - } - - [Fact] - public async Task ExecuteAsync_WithException_LogsError() - { - // Arrange - var processData = _fixture.CreateMany().Select(x => new Process(x, ProcessTypeId.SETUP_DIM, Guid.NewGuid())).ToImmutableArray(); - var error = new Exception("Only a test"); - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .Throws(error); - - Environment.ExitCode = 0; - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - Environment.ExitCode.Should().Be(0); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.IsNull(), A.That.Matches(x => x.StartsWith("start processing process")))).MustHaveHappened(3, Times.Exactly); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.Matches(e => e != null && e.Message == error.Message), A.That.StartsWith("error processing process"))).MustHaveHappened(3, Times.Exactly); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.IsNull(), A.That.Matches(x => x.StartsWith("finished processing process")))).MustNotHaveHappened(); - A.CallTo(() => _mockLogger.Log(LogLevel.Error, A._, A._)).MustNotHaveHappened(); - A.CallTo(() => _repositories.SaveAsync()).MustNotHaveHappened(); - } - - [Fact] - public async Task ExecuteAsync_WithSystemException_Exits() - { - // Arrange - var processData = _fixture.CreateMany().Select(x => new Process(x, ProcessTypeId.SETUP_DIM, Guid.NewGuid())).ToImmutableArray(); - var error = new SystemException("unrecoverable failure"); - A.CallTo(() => _processStepRepository.GetActiveProcesses(A>._, A>._, A._)) - .Returns(processData.ToAsyncEnumerable()); - A.CallTo(() => _processExecutor.ExecuteProcess(A._, A._, A._)) - .Throws(error); - - Environment.ExitCode = 0; - - // Act - await _service.ExecuteAsync(CancellationToken.None); - - // Assert - Environment.ExitCode.Should().Be(1); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.IsNull(), A.That.Matches(x => x.StartsWith("start processing process")))).MustHaveHappenedOnceExactly(); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.IsNotNull(), A._)).MustNotHaveHappened(); - A.CallTo(() => _mockLogger.Log(LogLevel.Information, A.That.IsNull(), A.That.Matches(x => x.StartsWith("finished processing process")))).MustNotHaveHappened(); - A.CallTo(() => _mockLogger.Log(LogLevel.Error, A.That.Matches(e => e != null && e.Message == error.Message), $"processing failed with following Exception {error.Message}")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _repositories.SaveAsync()).MustNotHaveHappened(); - } -} diff --git a/tests/processes/Processes.Worker.Library.Tests/ProcessExecutorTests.cs b/tests/processes/Processes.Worker.Library.Tests/ProcessExecutorTests.cs deleted file mode 100644 index 0e20982..0000000 --- a/tests/processes/Processes.Worker.Library.Tests/ProcessExecutorTests.cs +++ /dev/null @@ -1,877 +0,0 @@ -/******************************************************************************** - * 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.DbAccess; -using Dim.DbAccess.Repositories; -using Dim.Entities.Entities; -using Dim.Entities.Enums; -using Microsoft.Extensions.Logging; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; -using System.Collections.Immutable; -using ProcessTypeId = Dim.Entities.Enums.ProcessTypeId; - -namespace Processes.Worker.Library.Tests; - -public class ProcessExecutorTests -{ - private readonly IProcessTypeExecutor _processTypeExecutor; - private readonly IProcessStepRepository _processStepRepository; - private readonly IProcessExecutor _sut; - private readonly IFixture _fixture; - - public ProcessExecutorTests() - { - _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); - _fixture.Behaviors.OfType().ToList() - .ForEach(b => _fixture.Behaviors.Remove(b)); - _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); - - _processTypeExecutor = A.Fake(); - _processStepRepository = A.Fake(); - - var dimRepositories = A.Fake(); - var logger = A.Fake>(); - - A.CallTo(() => dimRepositories.GetInstance()) - .Returns(_processStepRepository); - - A.CallTo(() => _processTypeExecutor.GetProcessTypeId()) - .Returns(ProcessTypeId.SETUP_DIM); - - _sut = new ProcessExecutor( - new[] { _processTypeExecutor }, - dimRepositories, - logger); - } - - #region GetRegisteredProcessTypeIds - - [Fact] - public void GetRegisteredProcessTypeIds_ReturnsExpected() - { - // Act - var result = _sut.GetRegisteredProcessTypeIds(); - - // Assert - result.Should().HaveCount(1).And.Contain(ProcessTypeId.SETUP_DIM); - } - - #endregion - - #region ExecuteProcess - - [Fact] - public async Task ExecuteProcess_WithInvalidProcessTypeId_Throws() - { - // Arrange - var Act = async () => await _sut.ExecuteProcess(Guid.NewGuid(), default, CancellationToken.None).ToListAsync(); - - // Act - var result = await Assert.ThrowsAsync(Act); - - // Assert - result.Message.Should().Be("processType 0 is not a registered executable processType."); - } - - [Theory] - [InlineData(ProcessStepStatusId.DONE, true, new[] { - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.DONE, false, new[] { - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.TODO, true, new[] { - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - [InlineData(ProcessStepStatusId.TODO, false, new[] { - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - public async Task ExecuteProcess_WithInitialSteps_ReturnsExpected(ProcessStepStatusId stepStatusId, bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var processStepTypeId = _fixture.Create(); - var processStepData = (Id: Guid.NewGuid(), processStepTypeId); - var initialStepTypeIds = Enum.GetValues().Where(x => x != processStepTypeId).Take(3).ToImmutableArray(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(new[] { processStepData }.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, initialStepTypeIds)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, null, null, null)); - - IEnumerable? createdProcessSteps = null; - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) => - { - createdProcessSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToImmutableList(); - return createdProcessSteps; - }); - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .Invokes((Guid stepId, Action? initialize, Action modify) => - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - }); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - // Assert - result.Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustHaveHappenedOnceExactly(); - - createdProcessSteps - .Should().NotBeNull() - .And.HaveSameCount(initialStepTypeIds) - .And.Satisfy( - x => x.ProcessStepTypeId == initialStepTypeIds[0] && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.ProcessStepTypeId == initialStepTypeIds[1] && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.ProcessStepTypeId == initialStepTypeIds[2] && x.ProcessStepStatusId == ProcessStepStatusId.TODO); - - if (stepStatusId == ProcessStepStatusId.DONE) - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(initialStepTypeIds.Length + 1, Times.Exactly); - modifiedProcessSteps - .Should().HaveCount(initialStepTypeIds.Length + 1) - .And.Satisfy( - x => x.Id == processStepData.Id && x.ProcessStepStatusId == stepStatusId, - x => x.Id == createdProcessSteps!.ElementAt(0).Id && x.ProcessStepStatusId == stepStatusId, - x => x.Id == createdProcessSteps!.ElementAt(1).Id && x.ProcessStepStatusId == stepStatusId, - x => x.Id == createdProcessSteps!.ElementAt(2).Id && x.ProcessStepStatusId == stepStatusId); - } - else - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustNotHaveHappened(); - } - } - - [Theory] - [InlineData(ProcessStepStatusId.DONE, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.DONE, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.TODO, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - [InlineData(ProcessStepStatusId.TODO, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - public async Task ExecuteProcess_NoScheduleOrSkippedSteps_ReturnsExpected(ProcessStepStatusId stepStatusId, bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var processStepData = _fixture.CreateMany(3).Select(stepTypeId => (Id: Guid.NewGuid(), StepTypeId: stepTypeId)).OrderBy(x => x.StepTypeId).ToImmutableArray(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(processStepData.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, null, null, null)); - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .Invokes((Guid stepId, Action? initialize, Action modify) => - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - }); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - // Assert - result.Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustNotHaveHappened(); - - if (stepStatusId == ProcessStepStatusId.DONE) - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(processStepData.Length, Times.Exactly); - - modifiedProcessSteps - .Should().HaveSameCount(processStepData) - .And.Satisfy( - x => x.Id == processStepData[0].Id && x.ProcessStepStatusId == stepStatusId, - x => x.Id == processStepData[1].Id && x.ProcessStepStatusId == stepStatusId, - x => x.Id == processStepData[2].Id && x.ProcessStepStatusId == stepStatusId); - } - else - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustNotHaveHappened(); - } - } - - [Fact] - public async Task ExecuteProcess_NoExecutableSteps_ReturnsExpected() - { - // Arrange - var processId = Guid.NewGuid(); - var processStepData = _fixture.CreateMany().Select(stepTypeId => (Id: Guid.NewGuid(), StepTypeId: stepTypeId)).OrderBy(x => x.StepTypeId).ToImmutableArray(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(processStepData.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(false); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - // Assert - result.Should().HaveCount(1).And.Contain(IProcessExecutor.ProcessExecutionResult.Unmodified); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .MustNotHaveHappened(); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustNotHaveHappened(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustNotHaveHappened(); - } - - [Theory] - [InlineData(ProcessStepStatusId.DONE, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.DONE, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.TODO, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - [InlineData(ProcessStepStatusId.TODO, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - public async Task ExecuteProcess_NoScheduleOrSkippedSteps_SingleStepTypeWithDuplicates_ReturnsExpected(ProcessStepStatusId stepStatusId, bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var stepTypeId = _fixture.Create(); - var processStepData = _fixture.CreateMany(3).Select(x => (Id: x, StepTypeId: stepTypeId)).OrderBy(x => x.StepTypeId).ToImmutableArray(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(processStepData.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, null, null, null)); - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .Invokes((Guid stepId, Action? initialize, Action modify) => - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - }); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - // Assert - result.Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .MustHaveHappenedOnceExactly(); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustNotHaveHappened(); - - if (stepStatusId == ProcessStepStatusId.DONE) - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(processStepData.Length, Times.Exactly); - modifiedProcessSteps - .Should().HaveSameCount(processStepData) - .And.Satisfy( - x => x.Id == processStepData[0].Id, - x => x.Id == processStepData[1].Id, - x => x.Id == processStepData[2].Id) - .And.Satisfy( - x => x.ProcessStepStatusId == stepStatusId, - x => x.ProcessStepStatusId == ProcessStepStatusId.DUPLICATE, - x => x.ProcessStepStatusId == ProcessStepStatusId.DUPLICATE); - } - else - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustNotHaveHappened(); - } - } - - [Theory] - [InlineData(ProcessStepStatusId.DONE, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.DONE, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.TODO, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - [InlineData(ProcessStepStatusId.TODO, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - public async Task ExecuteProcess_WithScheduledSteps_ReturnsExpected(ProcessStepStatusId stepStatusId, bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var processStepData = (Id: Guid.NewGuid(), StepTypeId: _fixture.Create()); - var scheduleStepTypeIds = Enum.GetValues().Where(x => x != processStepData.StepTypeId).Take(3).ToImmutableArray(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(new[] { processStepData }.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(processStepData.StepTypeId, A>._, A._)) - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, scheduleStepTypeIds, null, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A.That.Not.IsEqualTo(processStepData.StepTypeId), A>._, A._)) - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, null, null, null)); - - IEnumerable? createdProcessSteps = null; - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) => - { - createdProcessSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToImmutableList(); - return createdProcessSteps; - }); - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .Invokes((Guid stepId, Action? initialize, Action modify) => - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - }); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - // Assert - result. - Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .MustHaveHappened(scheduleStepTypeIds.Length + 1, Times.Exactly); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustHaveHappenedOnceExactly(); - - createdProcessSteps - .Should().NotBeNull() - .And.HaveSameCount(scheduleStepTypeIds) - .And.Satisfy( - x => x.ProcessStepTypeId == scheduleStepTypeIds[0] && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.ProcessStepTypeId == scheduleStepTypeIds[1] && x.ProcessStepStatusId == ProcessStepStatusId.TODO, - x => x.ProcessStepTypeId == scheduleStepTypeIds[2] && x.ProcessStepStatusId == ProcessStepStatusId.TODO); - - if (stepStatusId == ProcessStepStatusId.DONE) - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(scheduleStepTypeIds.Length + 1, Times.Exactly); - modifiedProcessSteps - .Should().HaveCount(scheduleStepTypeIds.Length + 1) - .And.Satisfy( - x => x.Id == processStepData.Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE, - x => x.Id == createdProcessSteps!.ElementAt(0).Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE, - x => x.Id == createdProcessSteps!.ElementAt(1).Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE, - x => x.Id == createdProcessSteps!.ElementAt(2).Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE); - } - else - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustNotHaveHappened(); - } - } - - [Theory] - [InlineData(ProcessStepStatusId.DONE, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.DONE, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.TODO, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - [InlineData(ProcessStepStatusId.TODO, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified - })] - public async Task ExecuteProcess_WithDuplicateScheduledSteps_ReturnsExpected(ProcessStepStatusId stepStatusId, bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var stepTypeId = _fixture.Create(); - var processStepData = (Id: Guid.NewGuid(), StepTypeId: stepTypeId); - var scheduleStepTypeIds = Enumerable.Repeat(stepTypeId, 3); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(new[] { processStepData }.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(stepTypeId, A>._, A._)) - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, scheduleStepTypeIds, null, null)) - .Once() - .Then - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, null, null, null)); - - IEnumerable? createdProcessSteps = null; - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) => - { - createdProcessSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToImmutableList(); - return createdProcessSteps; - }); - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .Invokes((Guid stepId, Action? initialize, Action modify) => - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - }); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - result.Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - // Assert - if (stepStatusId == ProcessStepStatusId.DONE) - { - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustHaveHappenedOnceExactly(); - - createdProcessSteps - .Should().NotBeNull() - .And.HaveCount(1) - .And.Satisfy( - x => x.ProcessStepTypeId == stepTypeId && x.ProcessStepStatusId == ProcessStepStatusId.TODO); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .MustHaveHappened(2, Times.Exactly); - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(2, Times.Exactly); - - modifiedProcessSteps - .Should().HaveCount(2) - .And.Satisfy( - x => x.Id == processStepData.Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE, - x => x.Id == createdProcessSteps!.ElementAt(0).Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE); - } - else - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustNotHaveHappened(); - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustNotHaveHappened(); - } - } - - [Theory] - [InlineData(ProcessStepStatusId.DONE, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.DONE, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.TODO, true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(ProcessStepStatusId.TODO, false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - public async Task ExecuteProcess_WithSkippedSteps_ReturnsExpected(ProcessStepStatusId stepStatusId, bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var processStepData = _fixture.CreateMany(3).Select(stepTypeId => (Id: Guid.NewGuid(), StepTypeId: stepTypeId)).OrderBy(x => x.StepTypeId).ToImmutableArray(); - var skipStepTypeIds = processStepData.Skip(1).Select(x => x.StepTypeId).ToImmutableArray(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(processStepData.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .Returns(new IProcessTypeExecutor.StepExecutionResult(false, stepStatusId, null, skipStepTypeIds, null)); - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .Invokes((Guid stepId, Action? initialize, Action modify) => - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - }); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - // Assert - result.Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .MustHaveHappenedOnceExactly(); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustNotHaveHappened(); - - if (stepStatusId == ProcessStepStatusId.DONE) - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(skipStepTypeIds.Length + 1, Times.Exactly); - modifiedProcessSteps - .Should().HaveCount(skipStepTypeIds.Length + 1) - .And.Satisfy( - x => x.Id == processStepData[0].Id && x.ProcessStepStatusId == ProcessStepStatusId.DONE, - x => x.Id == processStepData[1].Id && x.ProcessStepStatusId == ProcessStepStatusId.SKIPPED, - x => x.Id == processStepData[2].Id && x.ProcessStepStatusId == ProcessStepStatusId.SKIPPED); - } - else - { - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(skipStepTypeIds.Length, Times.Exactly); - modifiedProcessSteps - .Should().HaveCount(skipStepTypeIds.Length) - .And.Satisfy( - x => x.Id == processStepData[1].Id && x.ProcessStepStatusId == ProcessStepStatusId.SKIPPED, - x => x.Id == processStepData[2].Id && x.ProcessStepStatusId == ProcessStepStatusId.SKIPPED); - } - } - - [Theory] - [InlineData(true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.LockRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - [InlineData(false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested, - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.SaveRequested - })] - public async Task ExecuteProcess_ProcessThrowsTestException_ReturnsExpected(bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var processStepData = _fixture.CreateMany(3).Select(stepTypeId => (Id: Guid.NewGuid(), StepTypeId: stepTypeId)).OrderBy(x => x.StepTypeId).ToImmutableArray(); - var error = _fixture.Create(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(processStepData.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .Throws(error); - - var modifiedProcessSteps = new List(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .Invokes((Guid stepId, Action? initialize, Action modify) => - { - var step = new ProcessStep(stepId, default, default, Guid.Empty, default); - initialize?.Invoke(step); - modify(step); - modifiedProcessSteps.Add(step); - }); - - // Act - var result = await _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None).ToListAsync(); - - // Assert - result.Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .MustHaveHappened(processStepData.Length, Times.Exactly); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustNotHaveHappened(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustHaveHappened(processStepData.Length, Times.Exactly); - - modifiedProcessSteps - .Should().HaveCount(processStepData.Length) - .And.Satisfy( - x => x.Id == processStepData[0].Id && x.ProcessStepStatusId == ProcessStepStatusId.FAILED, - x => x.Id == processStepData[1].Id && x.ProcessStepStatusId == ProcessStepStatusId.FAILED, - x => x.Id == processStepData[2].Id && x.ProcessStepStatusId == ProcessStepStatusId.FAILED); - } - - [Theory] - [InlineData(true, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - IProcessExecutor.ProcessExecutionResult.LockRequested, - })] - [InlineData(false, new[] { - IProcessExecutor.ProcessExecutionResult.Unmodified, - })] - public async Task ExecuteProcess_ProcessThrowsSystemException_Throws(bool isLockRequested, IEnumerable executionResults) - { - // Arrange - var processId = Guid.NewGuid(); - var processStepData = _fixture.CreateMany().Select(stepTypeId => (Id: Guid.NewGuid(), StepTypeId: stepTypeId)).OrderBy(x => x.StepTypeId).ToImmutableArray(); - var error = _fixture.Create(); - - A.CallTo(() => _processStepRepository.GetProcessStepData(processId)) - .Returns(processStepData.ToAsyncEnumerable()); - - A.CallTo(() => _processTypeExecutor.IsExecutableStepTypeId(A._)) - .Returns(true); - - A.CallTo(() => _processTypeExecutor.IsLockRequested(A._)) - .Returns(isLockRequested); - - A.CallTo(() => _processTypeExecutor.InitializeProcess(processId, A>._)) - .Returns(new IProcessTypeExecutor.InitializationResult(false, null)); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .Throws(error); - - var stepResults = new List(); - - var Act = async () => - { - await foreach (var stepResult in _sut.ExecuteProcess(processId, ProcessTypeId.SETUP_DIM, CancellationToken.None)) - { - stepResults.Add(stepResult); - } - }; - - // Act - var result = await Assert.ThrowsAsync(Act); - - // Assert - stepResults.Should().HaveSameCount(executionResults).And.ContainInOrder(executionResults); - - result.Message.Should().Be(error.Message); - - A.CallTo(() => _processTypeExecutor.ExecuteProcessStep(A._, A>._, A._)) - .MustHaveHappenedOnceExactly(); - - A.CallTo(() => _processStepRepository.AttachAndModifyProcessStep(A._, A>._, A>._)) - .MustNotHaveHappened(); - - A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) - .MustNotHaveHappened(); - } - - #endregion - - [Serializable] - public class TestException : Exception - { - public TestException() { } - public TestException(string message) : base(message) { } - public TestException(string message, Exception inner) : base(message, inner) { } - } -} diff --git a/tests/processes/Processes.Worker.Library.Tests/Processes.Worker.Library.Tests.csproj b/tests/processes/Processes.Worker.Library.Tests/Processes.Worker.Library.Tests.csproj deleted file mode 100644 index 92eaa86..0000000 --- a/tests/processes/Processes.Worker.Library.Tests/Processes.Worker.Library.Tests.csproj +++ /dev/null @@ -1,47 +0,0 @@ - - - - - net8.0 - enable - enable - false - Processes.Worker.Library.Tests - Processes.Worker.Library.Tests - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/tests/processes/Processes.Worker.Library.Tests/Usings.cs b/tests/processes/Processes.Worker.Library.Tests/Usings.cs deleted file mode 100644 index ded99ae..0000000 --- a/tests/processes/Processes.Worker.Library.Tests/Usings.cs +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************** - * 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; diff --git a/tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs b/tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs index 74b97f4..2c4a4ca 100644 --- a/tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs +++ b/tests/web/Dim.Web.Tests/DimBusinessLogicTests.cs @@ -31,6 +31,9 @@ using Microsoft.Extensions.Options; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Concrete.Entities; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums; using System.Security.Cryptography; namespace Dim.Web.Tests; @@ -42,7 +45,7 @@ public class DimBusinessLogicTests private readonly IDimClient _dimClient; private readonly ITenantRepository _tenantRepository; private readonly ITechnicalUserRepository _technicalUserRepository; - private readonly IProcessStepRepository _processStepRepository; + private readonly IProcessStepRepository _processStepRepository; private readonly DimSettings _settings; private readonly IFixture _fixture; @@ -58,11 +61,11 @@ public DimBusinessLogicTests() _tenantRepository = A.Fake(); _technicalUserRepository = A.Fake(); - _processStepRepository = A.Fake(); + _processStepRepository = A.Fake>(); A.CallTo(() => repositories.GetInstance()).Returns(_tenantRepository); A.CallTo(() => repositories.GetInstance()).Returns(_technicalUserRepository); - A.CallTo(() => repositories.GetInstance()).Returns(_processStepRepository); + A.CallTo(() => repositories.GetInstance>()).Returns(_processStepRepository); _settings = new DimSettings { @@ -112,7 +115,7 @@ public async Task StartSetupDim_WithNewData_CreatesExpected(string companyName, // Arrange var processId = Guid.NewGuid(); var processes = new List(); - var processSteps = new List(); + var processSteps = new List>(); var tenants = new List(); A.CallTo(() => _tenantRepository.IsTenantExisting(A._, A._)) .Returns(false); @@ -125,7 +128,7 @@ public async Task StartSetupDim_WithNewData_CreatesExpected(string companyName, A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) .Invokes((ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid pId) => { - processSteps.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, pId, DateTimeOffset.UtcNow)); + processSteps.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, pId, DateTimeOffset.UtcNow)); }); A.CallTo(() => _tenantRepository.CreateTenant(A._, A._, A._, A._, A._, A._)) @@ -326,7 +329,7 @@ public async Task CreateTechnicalUser_WithNewData_CreatesExpected(string name, s const string Bpn = "BPNL00001Test"; var processId = Guid.NewGuid(); var processes = new List(); - var processSteps = new List(); + var processSteps = new List>(); var technicalUsers = new List(); A.CallTo(() => _tenantRepository.GetTenantForBpn(Bpn)) .Returns((true, Guid.NewGuid())); @@ -339,7 +342,7 @@ public async Task CreateTechnicalUser_WithNewData_CreatesExpected(string name, s A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) .Invokes((ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid pId) => { - processSteps.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, pId, DateTimeOffset.UtcNow)); + processSteps.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, pId, DateTimeOffset.UtcNow)); }); A.CallTo(() => _technicalUserRepository.CreateTenantTechnicalUser(A._, A._, A._, A._)) @@ -386,7 +389,7 @@ public async Task DeleteTechnicalUser_WithValid_DeletesExpected() // Arrange const string Bpn = "BPNL00001Test"; var processId = Guid.NewGuid(); - var processSteps = new List(); + var processSteps = new List>(); var technicalUserData = new TechnicalUserData(Guid.NewGuid(), "test"); var technicalUser = new TechnicalUser(Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), "test", processId); A.CallTo(() => _technicalUserRepository.GetTechnicalUserForBpn(Bpn, technicalUserData.Name)) @@ -394,7 +397,7 @@ public async Task DeleteTechnicalUser_WithValid_DeletesExpected() A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) .Invokes((ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid pId) => { - processSteps.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, pId, DateTimeOffset.UtcNow)); + processSteps.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, pId, DateTimeOffset.UtcNow)); }); A.CallTo(() => _technicalUserRepository.AttachAndModifyTechnicalUser(A._, A>._, A>._)) .Invokes((Guid _, Action? initialize, Action modify) =>