diff --git a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs index 82f22ff7a1..e7d83486ec 100644 --- a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs +++ b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs @@ -112,8 +112,7 @@ public async Task Given_UserCanceledOrchestrationInstanceAddedToDbContext_WhenRe private static OrchestrationDescription CreateOrchestrationDescription() { var orchestrationDescription = new OrchestrationDescription( - name: "TestOrchestration", - version: 4, + uniqueName: new OrchestrationDescriptionUniqueName("TestOrchestration", 4), canBeScheduled: true, functionName: "TestOrchestrationFunction"); diff --git a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs index e45db84f5f..00b969d7ef 100644 --- a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs +++ b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs @@ -161,12 +161,12 @@ public async Task GivenScheduledOrchestrationInstancesInDatabase_WhenGetSchedule public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByName_ThenExpectedOrchestrationInstancesAreRetrieved() { // Arrange - var uniqueName1 = Guid.NewGuid().ToString(); - var existingOrchestrationDescription01 = CreateOrchestrationDescription(uniqueName1, version: 1); + var uniqueName1 = new OrchestrationDescriptionUniqueName(Guid.NewGuid().ToString(), 1); + var existingOrchestrationDescription01 = CreateOrchestrationDescription(uniqueName1); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescription01); - var uniqueName2 = Guid.NewGuid().ToString(); - var existingOrchestrationDescription02 = CreateOrchestrationDescription(uniqueName2, version: 1); + var uniqueName2 = new OrchestrationDescriptionUniqueName(Guid.NewGuid().ToString(), 1); + var existingOrchestrationDescription02 = CreateOrchestrationDescription(uniqueName2); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescription02); var basedOn01 = CreateOrchestrationInstance(existingOrchestrationDescription01); @@ -178,7 +178,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByName_ThenExp await _sut.UnitOfWork.CommitAsync(); // Act - var actual = await _sut.SearchAsync(existingOrchestrationDescription01.Name); + var actual = await _sut.SearchAsync(existingOrchestrationDescription01.UniqueName.Name); // Assert actual.Should() @@ -189,11 +189,11 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByName_ThenExp public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndVersion_ThenExpectedOrchestrationInstancesAreRetrieved() { // Arrange - var uniqueName = Guid.NewGuid().ToString(); - var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1); + var name = Guid.NewGuid().ToString(); + var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1); - var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(uniqueName, version: 2); + var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 2)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV2); var basedOnV1 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); @@ -205,7 +205,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndVersi await _sut.UnitOfWork.CommitAsync(); // Act - var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.Name, existingOrchestrationDescriptionV1.Version); + var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.UniqueName.Name, existingOrchestrationDescriptionV1.UniqueName.Version); // Assert actual.Should() @@ -216,11 +216,11 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndVersi public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndLifecycleState_ThenExpectedOrchestrationInstancesAreRetrieved() { // Arrange - var uniqueName = Guid.NewGuid().ToString(); - var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1); + var name = Guid.NewGuid().ToString(); + var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1); - var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(uniqueName, version: 2); + var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 2)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV2); var isPendingV1 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); @@ -242,7 +242,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndLifec await _sut.UnitOfWork.CommitAsync(); // Act - var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.Name, lifecycleState: OrchestrationInstanceLifecycleStates.Running); + var actual = await _sut.SearchAsync(existingOrchestrationDescriptionV1.UniqueName.Name, lifecycleState: OrchestrationInstanceLifecycleStates.Running); // Assert actual.Should() @@ -253,11 +253,11 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndLifec public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTerminationState_ThenExpectedOrchestrationInstancesAreRetrieved() { // Arrange - var uniqueName = Guid.NewGuid().ToString(); - var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1); + var name = Guid.NewGuid().ToString(); + var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1); - var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(uniqueName, version: 2); + var existingOrchestrationDescriptionV2 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 2)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV2); var isPendingV1 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); @@ -282,7 +282,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi // Act var actual = await _sut.SearchAsync( - existingOrchestrationDescriptionV1.Name, + existingOrchestrationDescriptionV1.UniqueName.Name, lifecycleState: OrchestrationInstanceLifecycleStates.Terminated, terminationState: OrchestrationInstanceTerminationStates.Succeeded); @@ -300,8 +300,8 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndStart startedAtClockMock01.Setup(m => m.GetCurrentInstant()) .Returns(startedAt01); - var uniqueName = Guid.NewGuid().ToString(); - var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1); + var name = Guid.NewGuid().ToString(); + var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1); var isPending = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); @@ -321,7 +321,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndStart // Act var actual = await _sut.SearchAsync( - existingOrchestrationDescriptionV1.Name, + existingOrchestrationDescriptionV1.UniqueName.Name, startedAtOrLater: startedAt01); // Assert @@ -338,8 +338,8 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi terminatedAtClockMock01.Setup(m => m.GetCurrentInstant()) .Returns(terminatedAt01); - var uniqueName = Guid.NewGuid().ToString(); - var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(uniqueName, version: 1); + var name = Guid.NewGuid().ToString(); + var existingOrchestrationDescriptionV1 = CreateOrchestrationDescription(new OrchestrationDescriptionUniqueName(name, 1)); await SeedDatabaseWithOrchestrationDescriptionAsync(existingOrchestrationDescriptionV1); var isPending = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); @@ -366,7 +366,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi // Act var actual = await _sut.SearchAsync( - existingOrchestrationDescriptionV1.Name, + existingOrchestrationDescriptionV1.UniqueName.Name, terminatedAtOrEarlier: terminatedAt01); // Assert @@ -374,11 +374,10 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi .BeEquivalentTo(new[] { isTerminated01 }); } - private static OrchestrationDescription CreateOrchestrationDescription(string? name = default, int? version = default) + private static OrchestrationDescription CreateOrchestrationDescription(OrchestrationDescriptionUniqueName? uniqueName = default) { var orchestrationDescription = new OrchestrationDescription( - name: name ?? "TestOrchestration", - version: version ?? 4, + uniqueName: uniqueName ?? new OrchestrationDescriptionUniqueName("TestOrchestration", 4), canBeScheduled: true, functionName: "TestOrchestrationFunction"); diff --git a/source/ProcessManager.Core/Application/Orchestration/IOrchestrationRegisterQueries.cs b/source/ProcessManager.Core/Application/Orchestration/IOrchestrationRegisterQueries.cs index bad6cf7c80..23841c29e7 100644 --- a/source/ProcessManager.Core/Application/Orchestration/IOrchestrationRegisterQueries.cs +++ b/source/ProcessManager.Core/Application/Orchestration/IOrchestrationRegisterQueries.cs @@ -23,5 +23,5 @@ internal interface IOrchestrationRegisterQueries { Task GetAsync(OrchestrationDescriptionId id); - Task GetOrDefaultAsync(string name, int version, bool? isEnabled); + Task GetOrDefaultAsync(OrchestrationDescriptionUniqueName uniqueName, bool? isEnabled); } diff --git a/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs b/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs index 60b8a692f2..35541dc2c9 100644 --- a/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs +++ b/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription; using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; using NodaTime; @@ -24,8 +25,7 @@ public interface IStartOrchestrationInstanceCommands /// Task StartNewOrchestrationInstanceAsync( OperatingIdentity identity, - string name, - int version, + OrchestrationDescriptionUniqueName uniqueName, TParameter inputParameter, IReadOnlyCollection skipStepsBySequence) where TParameter : class; @@ -35,8 +35,7 @@ Task StartNewOrchestrationInstanceAsync( /// Task ScheduleNewOrchestrationInstanceAsync( UserIdentity identity, - string name, - int version, + OrchestrationDescriptionUniqueName uniqueName, TParameter inputParameter, Instant runAt, IReadOnlyCollection skipStepsBySequence) diff --git a/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs b/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs index 2396dbb605..a63d5d9570 100644 --- a/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs +++ b/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs @@ -40,15 +40,13 @@ internal class OrchestrationInstanceManager( /// public async Task StartNewOrchestrationInstanceAsync( OperatingIdentity identity, - string name, - int version, + OrchestrationDescriptionUniqueName uniqueName, TParameter inputParameter, IReadOnlyCollection skipStepsBySequence) where TParameter : class { var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync( - name, - version, + uniqueName, inputParameter, skipStepsBySequence).ConfigureAwait(false); @@ -68,16 +66,14 @@ await RequestStartOfOrchestrationInstanceAsync( /// public async Task ScheduleNewOrchestrationInstanceAsync( UserIdentity userIdentity, - string name, - int version, + OrchestrationDescriptionUniqueName uniqueName, TParameter inputParameter, Instant runAt, IReadOnlyCollection skipStepsBySequence) where TParameter : class { var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync( - name, - version, + uniqueName, inputParameter, skipStepsBySequence).ConfigureAwait(false); @@ -124,15 +120,14 @@ public async Task CancelScheduledOrchestrationInstanceAsync(UserIdentity userIde /// Validate orchestration description is known and that paramter value is valid according to its parameter definition. /// private async Task GuardMatchingOrchestrationDescriptionAsync( - string name, - int version, + OrchestrationDescriptionUniqueName uniqueName, TParameter inputParameter, IReadOnlyCollection skipStepsBySequence) where TParameter : class { - var orchestrationDescription = await _orchestrationRegister.GetOrDefaultAsync(name, version, isEnabled: true).ConfigureAwait(false); + var orchestrationDescription = await _orchestrationRegister.GetOrDefaultAsync(uniqueName, isEnabled: true).ConfigureAwait(false); if (orchestrationDescription == null) - throw new InvalidOperationException($"No enabled orchestration description matches Name='{name}' and Version='{version}'."); + throw new InvalidOperationException($"No enabled orchestration description matches UniqueName='{uniqueName}'."); var isValidParameterValue = await orchestrationDescription.ParameterDefinition.IsValidParameterValueAsync(inputParameter).ConfigureAwait(false); if (isValidParameterValue == false) diff --git a/source/ProcessManager.Core/Application/Registration/OrchestrationRegisterExtensions.cs b/source/ProcessManager.Core/Application/Registration/OrchestrationRegisterExtensions.cs index 5f138c9958..e7e067bd0f 100644 --- a/source/ProcessManager.Core/Application/Registration/OrchestrationRegisterExtensions.cs +++ b/source/ProcessManager.Core/Application/Registration/OrchestrationRegisterExtensions.cs @@ -42,8 +42,7 @@ public static async Task SynchronizeAsync( { var hostDescription = hostDescriptions .SingleOrDefault(x => - x.Name == registerDescription.Name - && x.Version == registerDescription.Version); + x.UniqueName == registerDescription.UniqueName); if (hostDescription == null) await register.DeregisterAsync(registerDescription).ConfigureAwait(false); @@ -54,8 +53,7 @@ public static async Task SynchronizeAsync( { var registerDescription = registerDescriptions .SingleOrDefault(x => - x.Name == hostDescription.Name - && x.Version == hostDescription.Version); + x.UniqueName == hostDescription.UniqueName); if (registerDescription == null || registerDescription.IsEnabled == false) await register.RegisterAsync(hostDescription, hostName).ConfigureAwait(false); diff --git a/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescription.cs b/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescription.cs index fa7810a93e..b95571630b 100644 --- a/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescription.cs +++ b/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescription.cs @@ -24,14 +24,12 @@ public class OrchestrationDescription private readonly List _steps; public OrchestrationDescription( - string name, - int version, + OrchestrationDescriptionUniqueName uniqueName, bool canBeScheduled, string functionName) { Id = new OrchestrationDescriptionId(Guid.NewGuid()); - Name = name; - Version = version; + UniqueName = uniqueName; CanBeScheduled = canBeScheduled; FunctionName = functionName; ParameterDefinition = new(); @@ -55,14 +53,9 @@ private OrchestrationDescription() public OrchestrationDescriptionId Id { get; } /// - /// A name which combined with the uniquely identifies the orchestration. + /// Uniquely identifies a specific implementation of the orchestration. /// - public string Name { get; } - - /// - /// A version which combined with the uniquely identifies the orchestration. - /// - public int Version { get; } + public OrchestrationDescriptionUniqueName UniqueName { get; } /// /// Specifies if the orchestration supports scheduling. diff --git a/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescriptionId.cs b/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescriptionId.cs index a88f3ffc93..78ebcd7bb1 100644 --- a/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescriptionId.cs +++ b/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescriptionId.cs @@ -14,4 +14,12 @@ namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription; -public record OrchestrationDescriptionId(Guid Value); +public record OrchestrationDescriptionId +{ + internal OrchestrationDescriptionId(Guid value) + { + Value = value; + } + + public Guid Value { get; } +} diff --git a/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescriptionUniqueName.cs b/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescriptionUniqueName.cs new file mode 100644 index 0000000000..4b13954d6f --- /dev/null +++ b/source/ProcessManager.Core/Domain/OrchestrationDescription/OrchestrationDescriptionUniqueName.cs @@ -0,0 +1,47 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription; + +/// +/// Uniquely identifies a specific implementation of the orchestration. +/// +public record OrchestrationDescriptionUniqueName +{ + /// + /// Access modifier is set so we nudge consumers from outside Proces Manager to + /// inherit from the record and hopefully create specific implementations per + /// orchestration so we get kind of "named" orchestrations modelled in records. + /// We allow internal use to support easy testing where we then don't have to + /// implement specifci "named" orchestrations. + /// + protected internal OrchestrationDescriptionUniqueName(string name, int version) + { + // Explicit guard for empty string + ArgumentException.ThrowIfNullOrWhiteSpace(name); + + Name = name; + Version = version; + } + + /// + /// A common name to identity the orchestration. + /// + public string Name { get; } + + /// + /// A version identifying a specific implementation of the orchestration. + /// + public int Version { get; } +} diff --git a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs index 685e2b9915..dd55acc1f6 100644 --- a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs +++ b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs @@ -31,12 +31,20 @@ public void Configure(EntityTypeBuilder builder) id => id.Value, dbValue => new OrchestrationDescriptionId(dbValue)); - builder.Property(o => o.Name); - builder.Property(o => o.Version); + builder.ComplexProperty( + o => o.UniqueName, + b => + { + b.Property(un => un.Name) + .HasColumnName(nameof(OrchestrationDescriptionUniqueName.Name)); + b.Property(un => un.Version) + .HasColumnName(nameof(OrchestrationDescriptionUniqueName.Version)); + }); + builder.Property(o => o.CanBeScheduled); builder.Property(o => o.FunctionName); - builder.OwnsOne( + builder.ComplexProperty( o => o.ParameterDefinition, b => { diff --git a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs index 0848e650ba..e4328efe21 100644 --- a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs +++ b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs @@ -32,6 +32,8 @@ public void Configure(EntityTypeBuilder builder) id => id.Value, dbValue => new OrchestrationInstanceId(dbValue)); + // Unfortunately we cannot use 'ComplexProperty' as it doesn't yet support nullability + // and we need to be able to set 'CanceledBy' as null. builder.OwnsOne( o => o.Lifecycle, b => @@ -68,7 +70,7 @@ public void Configure(EntityTypeBuilder builder) }); }); - builder.OwnsOne( + builder.ComplexProperty( o => o.ParameterValue, b => { diff --git a/source/ProcessManager.Core/Infrastructure/Orchestration/OrchestrationInstanceRepository.cs b/source/ProcessManager.Core/Infrastructure/Orchestration/OrchestrationInstanceRepository.cs index f558fc1f4f..00ffb9dceb 100644 --- a/source/ProcessManager.Core/Infrastructure/Orchestration/OrchestrationInstanceRepository.cs +++ b/source/ProcessManager.Core/Infrastructure/Orchestration/OrchestrationInstanceRepository.cs @@ -75,8 +75,8 @@ public async Task> SearchAsync( var query = _context .OrchestrationDescriptions - .Where(x => x.Name == name) - .Where(x => version == null || x.Version == version) + .Where(x => x.UniqueName.Name == name) + .Where(x => version == null || x.UniqueName.Version == version) .Join( _context.OrchestrationInstances, description => description.Id, diff --git a/source/ProcessManager.Core/Infrastructure/Registration/OrchestrationRegister.cs b/source/ProcessManager.Core/Infrastructure/Registration/OrchestrationRegister.cs index c6fd6e1d89..80b6f388e3 100644 --- a/source/ProcessManager.Core/Infrastructure/Registration/OrchestrationRegister.cs +++ b/source/ProcessManager.Core/Infrastructure/Registration/OrchestrationRegister.cs @@ -41,14 +41,11 @@ public Task GetAsync(OrchestrationDescriptionId id) } /// - public Task GetOrDefaultAsync(string name, int version, bool? isEnabled) + public Task GetOrDefaultAsync(OrchestrationDescriptionUniqueName uniqueName, bool? isEnabled) { - ArgumentException.ThrowIfNullOrWhiteSpace(name); - return _context.OrchestrationDescriptions .SingleOrDefaultAsync(x => - x.Name == name - && x.Version == version + x.UniqueName == uniqueName && (isEnabled == null || x.IsEnabled == isEnabled)); } @@ -69,7 +66,7 @@ public async Task RegisterAsync(OrchestrationDescription orchestrationDescriptio ArgumentNullException.ThrowIfNull(orchestrationDescription); ArgumentException.ThrowIfNullOrWhiteSpace(hostName); - var existing = await GetOrDefaultAsync(orchestrationDescription.Name, orchestrationDescription.Version, isEnabled: null).ConfigureAwait(false); + var existing = await GetOrDefaultAsync(orchestrationDescription.UniqueName, isEnabled: null).ConfigureAwait(false); if (existing == null) { // Enfore certain values @@ -90,7 +87,7 @@ public async Task DeregisterAsync(OrchestrationDescription orchestrationDescript { ArgumentNullException.ThrowIfNull(orchestrationDescription); - var existing = await GetOrDefaultAsync(orchestrationDescription.Name, orchestrationDescription.Version, isEnabled: true).ConfigureAwait(false); + var existing = await GetOrDefaultAsync(orchestrationDescription.UniqueName, isEnabled: true).ConfigureAwait(false); if (existing == null) throw new InvalidOperationException("Orchestration description has not been registered or is not currently enabled."); diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/Brs_023_027_V1.cs b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/Brs_023_027_V1.cs new file mode 100644 index 0000000000..c2ee6ab1a0 --- /dev/null +++ b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/Brs_023_027_V1.cs @@ -0,0 +1,20 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription; + +namespace Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_023_027.V1; + +public record Brs_023_027_V1() + : OrchestrationDescriptionUniqueName("BRS_023_027", 1); diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs index e12daee5a6..a338ebf92b 100644 --- a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs +++ b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs @@ -42,8 +42,7 @@ public async Task ScheduleNewCalculationAsync( identity: new UserIdentity( new UserId(command.OperatingIdentity.UserId), new ActorId(command.OperatingIdentity.ActorId)), - name: "BRS_023_027", - version: 1, + uniqueName: new Brs_023_027_V1(), inputParameter: command.InputParameter, runAt: command.RunAt.ToInstant(), skipStepsBySequence: skipStepsBySequence) diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/Brs_026_V1.cs b/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/Brs_026_V1.cs new file mode 100644 index 0000000000..2a693affbc --- /dev/null +++ b/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/Brs_026_V1.cs @@ -0,0 +1,20 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescription; + +namespace Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_026.V1; + +public record Brs_026_V1() + : OrchestrationDescriptionUniqueName("BRS_026", 1); diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs b/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs index eba6f2fafd..6df1db4171 100644 --- a/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs +++ b/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs @@ -30,8 +30,7 @@ public async Task StartRequestCalculatedEnergyTimeSeriesAsync(RequestCalculatedE { await _commands.StartNewOrchestrationInstanceAsync( identity: new ActorIdentity(new ActorId(Guid.NewGuid())), // TODO: Any call to commands must include identity information; see 'ScheduleOrchestrationInstanceDto' and 'CancelOrchestrationInstanceDto' - "BRS_026", - 1, + uniqueName: new Brs_026_V1(), input, []) .ConfigureAwait(false); diff --git a/source/ProcessManager.Orchestrations/Program.cs b/source/ProcessManager.Orchestrations/Program.cs index 0d46225e22..197b48289a 100644 --- a/source/ProcessManager.Orchestrations/Program.cs +++ b/source/ProcessManager.Orchestrations/Program.cs @@ -45,8 +45,8 @@ // We could implement an interface for "description building" which could then be implemented besides the orchestration. // During DI we could then search for all these interface implementations and register them automatically. // This would ensure we didn't have to update Program.cs when we change orchestrations. - var brs_023_027_v1 = CreateBRS_023_027_V1Description(); - var brs_026_v1 = CreateBRS_026_V1Description(); + var brs_023_027_v1 = CreateBrs_023_027_V1Description(); + var brs_026_v1 = CreateBrs_026_V1Description(); return [brs_023_027_v1, brs_026_v1]; }); @@ -62,34 +62,36 @@ await host.SynchronizeWithOrchestrationRegisterAsync("ProcessManager.Orchestrations").ConfigureAwait(false); await host.RunAsync().ConfigureAwait(false); -OrchestrationDescription CreateBRS_023_027_V1Description() +OrchestrationDescription CreateBrs_023_027_V1Description() { - var brs023027V1 = new OrchestrationDescription( - name: "BRS_023_027", - version: 1, + var description = new OrchestrationDescription( + uniqueName: new Brs_023_027_V1(), canBeScheduled: true, functionName: nameof(NotifyAggregatedMeasureDataOrchestrationV1)); - brs023027V1.ParameterDefinition.SetFromType(); + description.ParameterDefinition.SetFromType(); - brs023027V1.AppendStepDescription("Beregning"); - brs023027V1.AppendStepDescription( + description.AppendStepDescription("Beregning"); + description.AppendStepDescription( "Besked dannelse", canBeSkipped: true, skipReason: "Do not perform this step for an internal calculation."); - return brs023027V1; + + return description; } -OrchestrationDescription CreateBRS_026_V1Description() +OrchestrationDescription CreateBrs_026_V1Description() { - var brs026V1 = new OrchestrationDescription( - name: "BRS_026", - version: 1, + var description = new OrchestrationDescription( + uniqueName: new Brs_026_V1(), canBeScheduled: false, functionName: nameof(RequestCalculatedEnergyTimeSeriesOrchestrationV1)); - brs026V1.ParameterDefinition.SetFromType(); - brs026V1.AppendStepDescription("Asynkron validering"); - brs026V1.AppendStepDescription("Hent anmodningsdata"); - brs026V1.AppendStepDescription("Udsend beskeder"); - return brs026V1; + + description.ParameterDefinition.SetFromType(); + + description.AppendStepDescription("Asynkron validering"); + description.AppendStepDescription("Hent anmodningsdata"); + description.AppendStepDescription("Udsend beskeder"); + + return description; } diff --git a/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs b/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs index f5d3deae3c..5de7dfe7ff 100644 --- a/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs +++ b/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs @@ -73,8 +73,7 @@ public void MapToDto_WhenOrchestrationInstanceWithOperatingIdentity_Deserialized private static OrchestrationInstance CreateOrchestrationInstance(OperatingIdentity? createdBy = default) { var orchestrationDescription = new OrchestrationDescription( - name: "name", - version: 1, + uniqueName: new OrchestrationDescriptionUniqueName("name", 1), canBeScheduled: false, functionName: "functionName");