Skip to content

Commit

Permalink
feat(clearinghouse): add feature toggle for sd connectivity
Browse files Browse the repository at this point in the history
Refs: #792
  • Loading branch information
Phil91 committed Jun 24, 2024
1 parent b41820c commit e7795a4
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 118 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public class ConnectorsSettings
/// </summary>
[Required(AllowEmptyStrings = false)]
public string SelfDescriptionDocumentUrl { get; set; } = null!;

/// <summary>
/// If <c>true</c> all sd factory calls are disabled and won't be called. The respective process steps will be skipped.
/// </summary>
public bool ClearinghouseConnectDisabled { get; set; }
}

public static class ConnectorsSettingsExtensions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

using Microsoft.Extensions.Options;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories;
Expand All @@ -28,31 +29,38 @@

namespace Org.Eclipse.TractusX.Portal.Backend.SdFactory.Library.BusinessLogic;

public class SdFactoryBusinessLogic : ISdFactoryBusinessLogic
public class SdFactoryBusinessLogic(
ISdFactoryService sdFactoryService,
IPortalRepositories portalRepositories,
IApplicationChecklistService checklistService,
IOptions<SdFactorySettings> options)
: ISdFactoryBusinessLogic
{
private readonly ISdFactoryService _sdFactoryService;
private readonly IPortalRepositories _portalRepositories;
private readonly IApplicationChecklistService _checklistService;

public SdFactoryBusinessLogic(ISdFactoryService sdFactoryService, IPortalRepositories portalRepositories,
IApplicationChecklistService checklistService)
{
_sdFactoryService = sdFactoryService;
_portalRepositories = portalRepositories;
_checklistService = checklistService;
}
private readonly SdFactorySettings _settings = options.Value;

/// <inheritdoc />
public Task RegisterConnectorAsync(
Guid connectorId,
string selfDescriptionDocumentUrl,
string businessPartnerNumber,
CancellationToken cancellationToken) =>
_sdFactoryService.RegisterConnectorAsync(connectorId, selfDescriptionDocumentUrl, businessPartnerNumber, cancellationToken);
sdFactoryService.RegisterConnectorAsync(connectorId, selfDescriptionDocumentUrl, businessPartnerNumber, cancellationToken);

/// <inheritdoc />
public async Task<IApplicationChecklistService.WorkerChecklistProcessStepExecutionResult> StartSelfDescriptionRegistration(IApplicationChecklistService.WorkerChecklistProcessStepData context, CancellationToken cancellationToken)
{
if (_settings.ClearinghouseConnectDisabled)
{
return new IApplicationChecklistService.WorkerChecklistProcessStepExecutionResult(
ProcessStepStatusId.DONE,
entry => entry.ApplicationChecklistEntryStatusId = ApplicationChecklistEntryStatusId.DONE,
new[] { ProcessStepTypeId.ACTIVATE_APPLICATION },
null,
true,
null
);
}

await RegisterSelfDescriptionInternalAsync(context.ApplicationId, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);

Expand All @@ -70,7 +78,7 @@ private async Task RegisterSelfDescriptionInternalAsync(
Guid applicationId,
CancellationToken cancellationToken)
{
var result = await _portalRepositories.GetInstance<IApplicationRepository>()
var result = await portalRepositories.GetInstance<IApplicationRepository>()
.GetCompanyAndApplicationDetailsWithUniqueIdentifiersAsync(applicationId)
.ConfigureAwait(ConfigureAwaitOptions.None);
if (result == default)
Expand All @@ -86,15 +94,15 @@ private async Task RegisterSelfDescriptionInternalAsync(
$"BusinessPartnerNumber (bpn) for CompanyApplications {applicationId} company {companyId} is empty");
}

await _sdFactoryService
await sdFactoryService
.RegisterSelfDescriptionAsync(applicationId, uniqueIdentifiers, countryCode, businessPartnerNumber, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);
}

public async Task ProcessFinishSelfDescriptionLpForApplication(SelfDescriptionResponseData data, Guid companyId, CancellationToken cancellationToken)
{
var confirm = ValidateData(data);
var context = await _checklistService
var context = await checklistService
.VerifyChecklistEntryAndProcessSteps(
data.ExternalId,
ApplicationChecklistEntryTypeId.SELF_DESCRIPTION_LP,
Expand All @@ -106,11 +114,11 @@ public async Task ProcessFinishSelfDescriptionLpForApplication(SelfDescriptionRe
if (confirm)
{
var documentId = await ProcessDocument(SdFactoryResponseModelTitle.LegalPerson, data, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
_portalRepositories.GetInstance<ICompanyRepository>().AttachAndModifyCompany(companyId, null,
portalRepositories.GetInstance<ICompanyRepository>().AttachAndModifyCompany(companyId, null,
c => { c.SelfDescriptionDocumentId = documentId; });
}

_checklistService.FinalizeChecklistEntryAndProcessSteps(
checklistService.FinalizeChecklistEntryAndProcessSteps(
context,
null,
item =>
Expand All @@ -133,7 +141,7 @@ public async Task ProcessFinishSelfDescriptionLpForConnector(SelfDescriptionResp
{
documentId = await ProcessDocument(SdFactoryResponseModelTitle.Connector, data, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
}
_portalRepositories.GetInstance<IConnectorsRepository>().AttachAndModifyConnector(data.ExternalId, null, con =>
portalRepositories.GetInstance<IConnectorsRepository>().AttachAndModifyConnector(data.ExternalId, null, con =>
{
if (documentId != null)
{
Expand Down Expand Up @@ -175,7 +183,7 @@ private async Task<Guid> ProcessDocument(SdFactoryResponseModelTitle title, Self
var documentContent = ms.ToArray();
var hash = SHA512.HashData(documentContent);

var document = _portalRepositories.GetInstance<IDocumentRepository>().CreateDocument(
var document = portalRepositories.GetInstance<IDocumentRepository>().CreateDocument(
$"SelfDescription_{title}.json",
documentContent,
hash,
Expand Down
22 changes: 4 additions & 18 deletions src/externalsystems/SdFactory.Library/SdFactoryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,14 @@ namespace Org.Eclipse.TractusX.Portal.Backend.SdFactory.Library;
/// <summary>
/// Service to handle communication with the connectors sd factory
/// </summary>
public class SdFactoryService : ISdFactoryService
public class SdFactoryService(ITokenService tokenService, IOptions<SdFactorySettings> options) : ISdFactoryService
{
private readonly ITokenService _tokenService;
private readonly SdFactorySettings _settings;

/// <summary>
/// Creates a new instance of <see cref="SdFactoryService"/>
/// </summary>
/// <param name="tokenService">Access to the token service</param>
/// <param name="options">The options</param>
public SdFactoryService(
ITokenService tokenService,
IOptions<SdFactorySettings> options)
{
_settings = options.Value;
_tokenService = tokenService;
}
private readonly SdFactorySettings _settings = options.Value;

/// <inheritdoc />
public async Task RegisterConnectorAsync(Guid connectorId, string selfDescriptionDocumentUrl, string businessPartnerNumber, CancellationToken cancellationToken)
{
var httpClient = await _tokenService.GetAuthorizedClient<SdFactoryService>(_settings, cancellationToken)
var httpClient = await tokenService.GetAuthorizedClient<SdFactoryService>(_settings, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);
var requestModel = new ConnectorSdFactoryRequestModel(
connectorId.ToString(),
Expand All @@ -70,7 +56,7 @@ await httpClient.PostAsJsonAsync(default(string?), requestModel, cancellationTok
/// <inheritdoc />
public async Task RegisterSelfDescriptionAsync(Guid applicationId, IEnumerable<(UniqueIdentifierId Id, string Value)> uniqueIdentifiers, string countryCode, string businessPartnerNumber, CancellationToken cancellationToken)
{
var httpClient = await _tokenService.GetAuthorizedClient<SdFactoryService>(_settings, cancellationToken)
var httpClient = await tokenService.GetAuthorizedClient<SdFactoryService>(_settings, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);
var requestModel = new SdFactoryRequestModel(
applicationId.ToString(),
Expand Down
5 changes: 5 additions & 0 deletions src/externalsystems/SdFactory.Library/SdFactorySettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ namespace Org.Eclipse.TractusX.Portal.Backend.SdFactory.Library;
/// </summary>
public class SdFactorySettings : KeyVaultAuthSettings
{
/// <summary>
/// If <c>true</c> all sd factory calls are disabled and won't be called. The respective process steps will be skipped.
/// </summary>
public bool ClearinghouseConnectDisabled { get; set; }

/// <summary>
/// SD Factory endpoint for registering connectors.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public class ConnectorsBusinessLogicTests
private readonly ConnectorsBusinessLogic _logic;
private readonly IDocumentRepository _documentRepository;
private readonly IServiceAccountRepository _serviceAccountRepository;
private readonly IOptions<ConnectorsSettings> _options;
private readonly IIdentityService _identityService;

public ConnectorsBusinessLogicTests()
{
Expand All @@ -75,10 +77,10 @@ public ConnectorsBusinessLogicTests()
_sdFactoryBusinessLogic = A.Fake<ISdFactoryBusinessLogic>();
_serviceAccountRepository = A.Fake<IServiceAccountRepository>();
_offerSubscriptionRepository = A.Fake<IOfferSubscriptionsRepository>();
var identityService = A.Fake<IIdentityService>();
_identityService = A.Fake<IIdentityService>();
_identity = A.Fake<IIdentityData>();
_connectors = new List<Connector>();
var options = A.Fake<IOptions<ConnectorsSettings>>();
_options = A.Fake<IOptions<ConnectorsSettings>>();
var settings = new ConnectorsSettings
{
MaxPageSize = 15,
Expand All @@ -92,13 +94,12 @@ public ConnectorsBusinessLogicTests()
_documentRepository = A.Fake<IDocumentRepository>();
SetupRepositoryMethods();

A.CallTo(() => options.Value).Returns(settings);
A.CallTo(() => identityService.IdentityData).Returns(_identity);
var logger = A.Fake<ILogger<ConnectorsBusinessLogic>>();
A.CallTo(() => _options.Value).Returns(settings);
A.CallTo(() => _identityService.IdentityData).Returns(_identity);

SetupIdentity();

_logic = new ConnectorsBusinessLogic(_portalRepositories, options, _sdFactoryBusinessLogic, identityService, logger);
_logic = new ConnectorsBusinessLogic(_portalRepositories, _options, _sdFactoryBusinessLogic, _identityService, A.Fake<ILogger<ConnectorsBusinessLogic>>());
}

#region GetAllCompanyConnectorDatas
Expand Down Expand Up @@ -133,19 +134,34 @@ public async Task GetAllCompanyConnectorDatas_WithValidData_ReturnsExpected(int

#region Create Connector

[Fact]
public async Task CreateConnectorAsync_WithValidInput_ReturnsCreatedConnectorData()
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task CreateConnectorAsync_WithValidInput_ReturnsCreatedConnectorData(bool clearingHouseDisabled)
{
// Arrange
var sut = new ConnectorsBusinessLogic(_portalRepositories, Options.Create(new ConnectorsSettings
{
MaxPageSize = 15,
ValidCertificationContentTypes = new[]
{
"application/x-pem-file",
"application/x-x509-ca-cert",
"application/pkix-cert"
},
ClearinghouseConnectDisabled = clearingHouseDisabled
}), _sdFactoryBusinessLogic, _identityService, A.Fake<ILogger<ConnectorsBusinessLogic>>());

var connectorInput = new ConnectorInputModel("connectorName", "https://test.de", "de", ServiceAccountUserId);

// Act
var result = await _logic.CreateConnectorAsync(connectorInput, CancellationToken.None);
var result = await sut.CreateConnectorAsync(connectorInput, CancellationToken.None);

// Assert
result.Should().NotBeEmpty();
_connectors.Should().HaveCount(1);
A.CallTo(() => _connectorsRepository.CreateConnectorAssignedSubscriptions(A<Guid>._, A<Guid>._)).MustNotHaveHappened();
A.CallTo(() => _sdFactoryBusinessLogic.RegisterConnectorAsync(A<Guid>._, A<string>._, A<string>._, A<CancellationToken>._)).MustHaveHappened(clearingHouseDisabled ? 0 : 1, Times.Exactly);
}

[Fact]
Expand Down Expand Up @@ -248,36 +264,66 @@ public async Task CreateConnectorAsync_WithFailingDapsService_ReturnsCreatedConn

#region CreateManagedConnectorAsync

[Fact]
public async Task CreateManagedConnectorAsync_WithValidInput_ReturnsCreatedConnectorData()
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task CreateManagedConnectorAsync_WithValidInput_ReturnsCreatedConnectorData(bool clearingHouseDisabled)
{
// Arrange
var sut = new ConnectorsBusinessLogic(_portalRepositories, Options.Create(new ConnectorsSettings
{
MaxPageSize = 15,
ValidCertificationContentTypes = new[]
{
"application/x-pem-file",
"application/x-x509-ca-cert",
"application/pkix-cert"
},
ClearinghouseConnectDisabled = clearingHouseDisabled
}), _sdFactoryBusinessLogic, _identityService, A.Fake<ILogger<ConnectorsBusinessLogic>>());

var connectorInput = new ManagedConnectorInputModel("connectorName", "https://test.de", "de", _validOfferSubscriptionId, ServiceAccountUserId);

// Act
var result = await _logic.CreateManagedConnectorAsync(connectorInput, CancellationToken.None);
var result = await sut.CreateManagedConnectorAsync(connectorInput, CancellationToken.None);

// Assert
result.Should().NotBeEmpty();
_connectors.Should().HaveCount(1);
A.CallTo(() => _connectorsRepository.CreateConnectorAssignedSubscriptions(A<Guid>._, _validOfferSubscriptionId)).MustHaveHappenedOnceExactly();
A.CallTo(() => _sdFactoryBusinessLogic.RegisterConnectorAsync(A<Guid>._, A<string>._, A<string>._, A<CancellationToken>._)).MustHaveHappened(clearingHouseDisabled ? 0 : 1, Times.Exactly);
}

[Fact]
public async Task CreateManagedConnectorAsync_WithTechnicalUser_ReturnsCreatedConnectorData()
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task CreateManagedConnectorAsync_WithTechnicalUser_ReturnsCreatedConnectorData(bool clearingHouseDisabled)
{
// Arrange
var sut = new ConnectorsBusinessLogic(_portalRepositories, Options.Create(new ConnectorsSettings
{
MaxPageSize = 15,
ValidCertificationContentTypes = new[]
{
"application/x-pem-file",
"application/x-x509-ca-cert",
"application/pkix-cert"
},
ClearinghouseConnectDisabled = clearingHouseDisabled
}), _sdFactoryBusinessLogic, _identityService, A.Fake<ILogger<ConnectorsBusinessLogic>>());

var connectorInput = new ManagedConnectorInputModel("connectorName", "https://test.de", "de", _validOfferSubscriptionId, null);

SetupTechnicalIdentity();

// Act
var result = await _logic.CreateManagedConnectorAsync(connectorInput, CancellationToken.None);
var result = await sut.CreateManagedConnectorAsync(connectorInput, CancellationToken.None);

// Assert
result.Should().NotBeEmpty();
_connectors.Should().HaveCount(1);
A.CallTo(() => _connectorsRepository.CreateConnectorAssignedSubscriptions(A<Guid>._, _validOfferSubscriptionId)).MustHaveHappenedOnceExactly();
A.CallTo(() => _sdFactoryBusinessLogic.RegisterConnectorAsync(A<Guid>._, A<string>._, A<string>._, A<CancellationToken>._)).MustHaveHappened(clearingHouseDisabled ? 0 : 1, Times.Exactly);
}

[Fact]
Expand Down
Loading

0 comments on commit e7795a4

Please sign in to comment.