From 5117a5d1b15d74c3a623db5112717408ab4bf523 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Wed, 24 Jul 2024 12:55:21 +0200 Subject: [PATCH] fix(offersubscription): skip optional autosetupprovidercallback if it is not configured (#865) --- .../OfferProviderBusinessLogic.cs | 35 +++++++---- .../Service/OfferSetupService.cs | 4 +- .../Models/TriggerProviderInformation.cs | 3 +- .../IOfferSubscriptionsRepository.cs | 2 +- .../OfferSubscriptionsRepository.cs | 9 +-- .../OfferProviderBusinessLogicTests.cs | 58 ++++++++++++++----- .../Service/OfferSetupServiceTests.cs | 21 +++++-- 7 files changed, 91 insertions(+), 41 deletions(-) diff --git a/src/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogic.cs b/src/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogic.cs index 3165fe22d8..06c9539def 100644 --- a/src/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogic.cs +++ b/src/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogic.cs @@ -82,10 +82,11 @@ await _offerProviderService } return ( - new[] { + [ data.IsSingleInstance ? ProcessStepTypeId.SINGLE_INSTANCE_SUBSCRIPTION_DETAILS_CREATION : - ProcessStepTypeId.START_AUTOSETUP }, + ProcessStepTypeId.START_AUTOSETUP + ], triggerProvider ? ProcessStepStatusId.DONE : ProcessStepStatusId.SKIPPED, true, null); @@ -100,6 +101,15 @@ await _offerProviderService throw new NotFoundException($"OfferSubscription {offerSubscriptionId} does not exist"); } + if (string.IsNullOrWhiteSpace(data.CallbackUrl)) + { + return ( + null, + ProcessStepStatusId.SKIPPED, + true, + null); + } + if (data.Status != OfferSubscriptionStatusId.ACTIVE) { throw new ConflictException("offer subscription should be active"); @@ -110,11 +120,6 @@ await _offerProviderService throw new ConflictException("Client should be set"); } - if (string.IsNullOrWhiteSpace(data.CallbackUrl)) - { - throw new ConflictException("Callback Url should be set here"); - } - if (data.ServiceAccounts.Count() > 1) { throw new ConflictException("There should be not more than one service account for the offer subscription"); @@ -123,16 +128,22 @@ await _offerProviderService CallbackTechnicalUserInfoData? technicalUserInfoData = null; if (data.ServiceAccounts.Count() == 1) { - var serviceAccount = data.ServiceAccounts.FirstOrDefault(); + var serviceAccount = data.ServiceAccounts.First(); if (serviceAccount.TechnicalClientId == null) { throw new ConflictException($"ClientId of serviceAccount {serviceAccount.TechnicalUserId} should be set"); } - var internalClientId = await _provisioningManager.GetIdOfCentralClientAsync(serviceAccount.TechnicalClientId).ConfigureAwait(ConfigureAwaitOptions.None); - var authData = await _provisioningManager.GetCentralClientAuthDataAsync(internalClientId).ConfigureAwait(ConfigureAwaitOptions.None); + async Task GetServiceAccountSecret(string technicalClientId) + { + var internalClientId = await _provisioningManager.GetIdOfCentralClientAsync(technicalClientId).ConfigureAwait(ConfigureAwaitOptions.None); + var authData = await _provisioningManager.GetCentralClientAuthDataAsync(internalClientId).ConfigureAwait(ConfigureAwaitOptions.None); + return authData.Secret; + } technicalUserInfoData = new CallbackTechnicalUserInfoData( serviceAccount.TechnicalUserId, - authData.Secret, + serviceAccount.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL + ? await GetServiceAccountSecret(serviceAccount.TechnicalClientId).ConfigureAwait(ConfigureAwaitOptions.None) + : null, serviceAccount.TechnicalClientId); } @@ -141,7 +152,7 @@ await _offerProviderService new CallbackClientInfoData(data.ClientId) ); await _offerProviderService - .TriggerOfferProviderCallback(callbackData, data.CallbackUrl!, cancellationToken) + .TriggerOfferProviderCallback(callbackData, data.CallbackUrl, cancellationToken) .ConfigureAwait(ConfigureAwaitOptions.None); return ( diff --git a/src/marketplace/Offers.Library/Service/OfferSetupService.cs b/src/marketplace/Offers.Library/Service/OfferSetupService.cs index e5281f71af..6892af40e4 100644 --- a/src/marketplace/Offers.Library/Service/OfferSetupService.cs +++ b/src/marketplace/Offers.Library/Service/OfferSetupService.cs @@ -678,7 +678,7 @@ public async Task TriggerActivateSubscription(Guid offerSubscriptionId) if (string.IsNullOrWhiteSpace(offerDetails.RequesterEmail)) { return new ValueTuple?, ProcessStepStatusId, bool, string?>( - offerDetails.InstanceData.IsSingleInstance ? null : new[] { ProcessStepTypeId.TRIGGER_PROVIDER_CALLBACK }, + offerDetails.InstanceData.IsSingleInstance || !offerDetails.HasCallbackUrl ? null : [ProcessStepTypeId.TRIGGER_PROVIDER_CALLBACK], ProcessStepStatusId.DONE, true, null); @@ -687,7 +687,7 @@ public async Task TriggerActivateSubscription(Guid offerSubscriptionId) SendMail(basePortalAddress, $"{offerDetails.RequesterFirstname} {offerDetails.RequesterLastname}", offerDetails.RequesterEmail, offerDetails.OfferName, offerDetails.OfferTypeId); return new ValueTuple?, ProcessStepStatusId, bool, string?>( - offerDetails.InstanceData.IsSingleInstance ? null : new[] { ProcessStepTypeId.TRIGGER_PROVIDER_CALLBACK }, + offerDetails.InstanceData.IsSingleInstance || !offerDetails.HasCallbackUrl ? null : [ProcessStepTypeId.TRIGGER_PROVIDER_CALLBACK], ProcessStepStatusId.DONE, true, null); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/TriggerProviderInformation.cs b/src/portalbackend/PortalBackend.DBAccess/Models/TriggerProviderInformation.cs index 61af7fe942..01b6e07092 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/TriggerProviderInformation.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/TriggerProviderInformation.cs @@ -49,5 +49,6 @@ public record SubscriptionActivationData( Guid? SalesManagerId, Guid? ProviderCompanyId, string? ClientClientId, - IEnumerable InternalServiceAccountClientIds + IEnumerable InternalServiceAccountClientIds, + bool HasCallbackUrl ); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs index f13e63de6d..5cbc47b6c8 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs @@ -155,7 +155,7 @@ public interface IOfferSubscriptionsRepository Task GetProcessStepData(Guid offerSubscriptionId, IEnumerable processStepTypeIds); Task GetClientCreationData(Guid offerSubscriptionId); Task GetTechnicalUserCreationData(Guid offerSubscriptionId); - Task<(IEnumerable<(Guid TechnicalUserId, string? TechnicalClientId)> ServiceAccounts, string? ClientId, string? CallbackUrl, OfferSubscriptionStatusId Status)> GetTriggerProviderCallbackInformation(Guid offerSubscriptionId); + Task<(IEnumerable<(Guid TechnicalUserId, string? TechnicalClientId, CompanyServiceAccountKindId CompanyServiceAccountKindId)> ServiceAccounts, string? ClientId, string? CallbackUrl, OfferSubscriptionStatusId Status)> GetTriggerProviderCallbackInformation(Guid offerSubscriptionId); OfferSubscriptionProcessData CreateOfferSubscriptionProcessData(Guid offerSubscriptionId, string offerUrl); void RemoveOfferSubscriptionProcessData(Guid offerSubscriptionProcessDataId); IAsyncEnumerable GetProcessStepsForSubscription(Guid offerSubscriptionId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs index f81b4a50bf..95e0538465 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs @@ -396,7 +396,8 @@ public Task GetOfferSubscriptionDataForProcessIdAsync(Guid processId) => x.Offer.OfferTypeId == OfferTypeId.APP && (x.Offer.AppInstanceSetup == null || !x.Offer.AppInstanceSetup!.IsSingleInstance) ? x.AppSubscriptionDetail!.AppInstance!.IamClient!.ClientClientId : null, - x.CompanyServiceAccounts.Where(sa => sa.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL && sa.ClientClientId != null).Select(sa => sa.ClientClientId!) + x.CompanyServiceAccounts.Where(sa => sa.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL && sa.ClientClientId != null).Select(sa => sa.ClientClientId!), + x.Offer.ProviderCompany!.ProviderCompanyDetail!.AutoSetupCallbackUrl != null )) .SingleOrDefaultAsync(); @@ -451,11 +452,11 @@ public Task GetOfferSubscriptionDataForProcessIdAsync(Guid processId) => .SingleOrDefaultAsync(); /// - public Task<(IEnumerable<(Guid TechnicalUserId, string? TechnicalClientId)> ServiceAccounts, string? ClientId, string? CallbackUrl, OfferSubscriptionStatusId Status)> GetTriggerProviderCallbackInformation(Guid offerSubscriptionId) => + public Task<(IEnumerable<(Guid TechnicalUserId, string? TechnicalClientId, CompanyServiceAccountKindId CompanyServiceAccountKindId)> ServiceAccounts, string? ClientId, string? CallbackUrl, OfferSubscriptionStatusId Status)> GetTriggerProviderCallbackInformation(Guid offerSubscriptionId) => _context.OfferSubscriptions .Where(x => x.Id == offerSubscriptionId) - .Select(x => new ValueTuple, string?, string?, OfferSubscriptionStatusId>( - x.CompanyServiceAccounts.Select(sa => new ValueTuple(sa.Id, sa.ClientClientId)), + .Select(x => new ValueTuple, string?, string?, OfferSubscriptionStatusId>( + x.CompanyServiceAccounts.Select(sa => new ValueTuple(sa.Id, sa.ClientClientId, sa.CompanyServiceAccountKindId)), x.AppSubscriptionDetail!.AppInstance!.IamClient!.ClientClientId, x.Offer!.ProviderCompany!.ProviderCompanyDetail!.AutoSetupCallbackUrl, x.OfferSubscriptionStatusId diff --git a/tests/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogicTests.cs b/tests/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogicTests.cs index 4ee6116a0e..b188f2db40 100644 --- a/tests/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogicTests.cs +++ b/tests/externalsystems/OfferProvider.Library/BusinessLogic/OfferProviderBusinessLogicTests.cs @@ -143,7 +143,7 @@ public async Task TriggerProviderCallback_InvalidSubscriptionId_Throws() // Arrange var fakeId = Guid.NewGuid(); A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(fakeId)) - .Returns<(IEnumerable<(Guid, string?)>, string?, string?, OfferSubscriptionStatusId)>(default); + .Returns<(IEnumerable<(Guid, string?, CompanyServiceAccountKindId)>, string?, string?, OfferSubscriptionStatusId)>(default); async Task Act() => await _sut.TriggerProviderCallback(fakeId, CancellationToken.None); // Act @@ -159,7 +159,7 @@ public async Task TriggerProviderCallback_WithPendingSubscription_Throws() // Arrange var fakeId = Guid.NewGuid(); A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(fakeId)) - .Returns((Enumerable.Empty<(Guid, string?)>(), string.Empty, null, OfferSubscriptionStatusId.PENDING)); + .Returns((Enumerable.Empty<(Guid, string?, CompanyServiceAccountKindId)>(), string.Empty, "callback", OfferSubscriptionStatusId.PENDING)); async Task Act() => await _sut.TriggerProviderCallback(fakeId, CancellationToken.None); // Act @@ -175,7 +175,7 @@ public async Task TriggerProviderCallback_WithClientIdNotSet_Throws() // Arrange var fakeId = Guid.NewGuid(); A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(fakeId)) - .Returns((Enumerable.Empty<(Guid, string?)>(), null, null, OfferSubscriptionStatusId.ACTIVE)); + .Returns((Enumerable.Empty<(Guid, string?, CompanyServiceAccountKindId)>(), null, "callback", OfferSubscriptionStatusId.ACTIVE)); async Task Act() => await _sut.TriggerProviderCallback(fakeId, CancellationToken.None); // Act @@ -186,19 +186,19 @@ public async Task TriggerProviderCallback_WithClientIdNotSet_Throws() } [Fact] - public async Task TriggerProviderCallback_WithCallbackUrlNotSet_Throws() + public async Task TriggerProviderCallback_WithCallbackUrlNotSet_Skips() { // Arrange var fakeId = Guid.NewGuid(); A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(fakeId)) - .Returns((Enumerable.Empty<(Guid, string?)>(), "cl1", null, OfferSubscriptionStatusId.ACTIVE)); - async Task Act() => await _sut.TriggerProviderCallback(fakeId, CancellationToken.None); + .Returns((Enumerable.Empty<(Guid, string?, CompanyServiceAccountKindId)>(), "cl1", null, OfferSubscriptionStatusId.ACTIVE)); // Act - var ex = await Assert.ThrowsAsync(Act); + var result = await _sut.TriggerProviderCallback(fakeId, CancellationToken.None); // Assert - ex.Message.Should().Be("Callback Url should be set here"); + result.nextStepTypeIds.Should().BeNull(); + result.stepStatusId.Should().Be(ProcessStepStatusId.SKIPPED); } [Fact] @@ -207,7 +207,7 @@ public async Task TriggerProviderCallback_WithNoServiceAccountSet_CallsExpected( // Arrange var fakeId = Guid.NewGuid(); A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(fakeId)) - .Returns((Enumerable.Empty<(Guid, string?)>(), "cl1", "https://callback.com", OfferSubscriptionStatusId.ACTIVE)); + .Returns((Enumerable.Empty<(Guid, string?, CompanyServiceAccountKindId)>(), "cl1", "https://callback.com", OfferSubscriptionStatusId.ACTIVE)); // Act var result = await _sut.TriggerProviderCallback(fakeId, CancellationToken.None); @@ -226,10 +226,10 @@ public async Task TriggerProviderCallback_WithMultipleServiceAccountSet_Throws() { // Arrange var fakeId = Guid.NewGuid(); - var serviceAccounts = new (Guid, string?)[] + var serviceAccounts = new (Guid, string?, CompanyServiceAccountKindId)[] { - new(Guid.NewGuid(), "sa1"), - new(Guid.NewGuid(), "sa2") + new(Guid.NewGuid(), "sa1", CompanyServiceAccountKindId.INTERNAL), + new(Guid.NewGuid(), "sa2", CompanyServiceAccountKindId.INTERNAL) }; A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(fakeId)) .Returns((serviceAccounts, "cl1", "https://callback.com", OfferSubscriptionStatusId.ACTIVE)); @@ -243,15 +243,15 @@ public async Task TriggerProviderCallback_WithMultipleServiceAccountSet_Throws() } [Fact] - public async Task TriggerProviderCallback_WithValidData_ReturnsExpected() + public async Task TriggerProviderCallback_WithValidData_InternalSA_ReturnsExpected() { // Arrange var technicalUserId = Guid.NewGuid(); var technicalUserClientId = "sa1"; var technicalUserInternalClientId = Guid.NewGuid().ToString(); - var serviceAccounts = new (Guid, string?)[] + var serviceAccounts = new (Guid, string?, CompanyServiceAccountKindId)[] { - new(technicalUserId, technicalUserClientId) + new(technicalUserId, technicalUserClientId, CompanyServiceAccountKindId.INTERNAL) }; A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(_subscriptionId)) .Returns((serviceAccounts, "cl1", "https://callback.com", OfferSubscriptionStatusId.ACTIVE)); @@ -271,6 +271,34 @@ public async Task TriggerProviderCallback_WithValidData_ReturnsExpected() .MustHaveHappenedOnceExactly(); } + [Fact] + public async Task TriggerProviderCallback_WithValidData_ExternalSA_ReturnsExpected() + { + // Arrange + var technicalUserId = Guid.NewGuid(); + var technicalUserClientId = "sa1"; + var serviceAccounts = new (Guid, string?, CompanyServiceAccountKindId)[] + { + new(technicalUserId, technicalUserClientId, CompanyServiceAccountKindId.EXTERNAL) + }; + A.CallTo(() => _offerSubscriptionRepository.GetTriggerProviderCallbackInformation(_subscriptionId)) + .Returns((serviceAccounts, "cl1", "https://callback.com", OfferSubscriptionStatusId.ACTIVE)); + + // Act + var result = await _sut.TriggerProviderCallback(_subscriptionId, CancellationToken.None); + + // Assert + result.nextStepTypeIds.Should().BeNull(); + result.stepStatusId.Should().Be(ProcessStepStatusId.DONE); + result.modified.Should().BeTrue(); + A.CallTo(() => _provisioningManager.GetIdOfCentralClientAsync(A._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.GetCentralClientAuthDataAsync(A._)) + .MustNotHaveHappened(); + A.CallTo(() => _offerProviderService.TriggerOfferProviderCallback(A.That.Matches(x => x.TechnicalUserInfo!.TechnicalUserSecret == null), A._, A._)) + .MustHaveHappenedOnceExactly(); + } + #endregion #region Setup diff --git a/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs b/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs index d55165e87e..55ad160255 100644 --- a/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs +++ b/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs @@ -1285,7 +1285,7 @@ public async Task ActivateSingleInstanceSubscription_WithValidData_ReturnsExpect A.CallTo(() => _notificationService.CreateNotificationsWithExistenceCheck(A>._, null, A>._, A._, A._, A._, A._)) .Returns(new[] { Guid.NewGuid() }.AsFakeIAsyncEnumerable(out var createNotificationsEnumerator)); A.CallTo(() => _offerSubscriptionsRepository.GetSubscriptionActivationDataByIdAsync(offerSubscription.Id)) - .Returns(new SubscriptionActivationData(_validOfferId, OfferSubscriptionStatusId.PENDING, OfferTypeId.APP, "Test App", "Stark Industries", _companyId, requesterEmail, "Tony", "Stark", Guid.NewGuid(), new(true, null), [Guid.NewGuid()], offerSubscriptionProcessDataId, Guid.NewGuid(), _companyId, null, Enumerable.Empty())); + .Returns(new SubscriptionActivationData(_validOfferId, OfferSubscriptionStatusId.PENDING, OfferTypeId.APP, "Test App", "Stark Industries", _companyId, requesterEmail, "Tony", "Stark", Guid.NewGuid(), new(true, null), [Guid.NewGuid()], offerSubscriptionProcessDataId, Guid.NewGuid(), _companyId, null, Enumerable.Empty(), true)); A.CallTo(() => _offerSubscriptionProcessService.VerifySubscriptionAndProcessSteps(offerSubscription.Id, ProcessStepTypeId.ACTIVATE_SUBSCRIPTION, null, true)) .Returns(new ManualProcessStepData(ProcessStepTypeId.ACTIVATE_SUBSCRIPTION, _fixture.Create(), [processStep], _portalRepositories)); @@ -1332,9 +1332,11 @@ public async Task ActivateSingleInstanceSubscription_WithValidData_ReturnsExpect } [Theory] - [InlineData(null)] - [InlineData("test@email.com")] - public async Task ActivateMultipleInstancesSubscription_WithValidData_ReturnsExpected(string? requesterEmail) + [InlineData(null, true)] + [InlineData("test@email.com", true)] + [InlineData(null, false)] + [InlineData("test@email.com", false)] + public async Task ActivateMultipleInstancesSubscription_WithValidData_ReturnsExpected(string? requesterEmail, bool hasCallbackUrl) { // Arrange var offerSubscription = new OfferSubscription(Guid.NewGuid(), _validOfferId, CompanyUserCompanyId, OfferSubscriptionStatusId.PENDING, _companyUserId, default); @@ -1347,7 +1349,7 @@ public async Task ActivateMultipleInstancesSubscription_WithValidData_ReturnsExp A.CallTo(() => _notificationService.CreateNotificationsWithExistenceCheck(A>._, null, A>._, A._, A._, A._, A._)) .Returns(new[] { Guid.NewGuid() }.AsFakeIAsyncEnumerable(out var createNotificationsEnumerator)); A.CallTo(() => _offerSubscriptionsRepository.GetSubscriptionActivationDataByIdAsync(offerSubscription.Id)) - .Returns(new SubscriptionActivationData(_validOfferId, OfferSubscriptionStatusId.PENDING, OfferTypeId.APP, "Test App", "Stark Industries", _companyId, requesterEmail, "Tony", "Stark", Guid.NewGuid(), new(false, null), [Guid.NewGuid()], offerSubscriptionProcessDataId, Guid.NewGuid(), _companyId, clientClientId, serviceAccountClientIds)); + .Returns(new SubscriptionActivationData(_validOfferId, OfferSubscriptionStatusId.PENDING, OfferTypeId.APP, "Test App", "Stark Industries", _companyId, requesterEmail, "Tony", "Stark", Guid.NewGuid(), new(false, null), [Guid.NewGuid()], offerSubscriptionProcessDataId, Guid.NewGuid(), _companyId, clientClientId, serviceAccountClientIds, hasCallbackUrl)); A.CallTo(() => _offerSubscriptionProcessService.VerifySubscriptionAndProcessSteps(offerSubscription.Id, ProcessStepTypeId.ACTIVATE_SUBSCRIPTION, null, true)) .Returns(new ManualProcessStepData(ProcessStepTypeId.ACTIVATE_SUBSCRIPTION, _fixture.Create(), [processStep], _portalRepositories)); @@ -1368,7 +1370,14 @@ public async Task ActivateMultipleInstancesSubscription_WithValidData_ReturnsExp var notificationTypeId = NotificationTypeId.APP_SUBSCRIPTION_ACTIVATION; offerSubscription.OfferSubscriptionStatusId.Should().Be(OfferSubscriptionStatusId.ACTIVE); - result.nextStepTypeIds.Should().ContainInOrder([ProcessStepTypeId.TRIGGER_PROVIDER_CALLBACK]); + if (hasCallbackUrl) + { + result.nextStepTypeIds.Should().ContainInOrder([ProcessStepTypeId.TRIGGER_PROVIDER_CALLBACK]); + } + else + { + result.nextStepTypeIds.Should().BeNull(); + } result.stepStatusId.Should().Be(ProcessStepStatusId.DONE); result.modified.Should().BeTrue(); result.processMessage.Should().BeNull();