Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(technicalkey): unexpected response for post policy-content - Purpose #97

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ public interface IPolicyRepository
IAsyncEnumerable<PolicyTypeResponse> GetPolicyTypes(PolicyTypeId? type, UseCaseId? useCase);
Task<(bool Exists, string LeftOperand, (AttributeKeyId? Key, IEnumerable<string> Values) Attributes, string? RightOperandValue)> GetPolicyContentAsync(UseCaseId? useCase, PolicyTypeId type, string credential);
IAsyncEnumerable<(string TechnicalKey, string LeftOperand, (AttributeKeyId? Key, IEnumerable<string> Values) Attributes, string? RightOperandValue)> GetPolicyForOperandContent(PolicyTypeId type, IEnumerable<string> technicalKeys);
Task<List<(string TechnicalKey, AttributeKeyId? AttributeKey, IEnumerable<string> Values)>> GetAttributeValuesForTechnicalKeys(PolicyTypeId type, IEnumerable<string> technicalKeys);
}
30 changes: 18 additions & 12 deletions src/database/PolicyHub.DbAccess/Repositories/PolicyRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,16 @@

namespace Org.Eclipse.TractusX.PolicyHub.DbAccess.Repositories;

public class PolicyRepository : IPolicyRepository
public class PolicyRepository(PolicyHubContext dbContext)
: IPolicyRepository
{
private readonly PolicyHubContext _dbContext;

public PolicyRepository(PolicyHubContext dbContext)
{
_dbContext = dbContext;
}

public IAsyncEnumerable<string> GetAttributeKeys() =>
_dbContext.AttributeKeys
dbContext.AttributeKeys
.Select(x => x.Label)
.AsAsyncEnumerable();

public IAsyncEnumerable<PolicyTypeResponse> GetPolicyTypes(PolicyTypeId? type, UseCaseId? useCase) =>
_dbContext.Policies
dbContext.Policies
.Where(p =>
(type == null || p.Types.Any(x => x.Id == type)) &&
(useCase == null || p.UseCases.Any(x => x.Id == useCase)))
Expand All @@ -54,7 +48,7 @@ public IAsyncEnumerable<PolicyTypeResponse> GetPolicyTypes(PolicyTypeId? type, U
.AsAsyncEnumerable();

public Task<(bool Exists, string LeftOperand, (AttributeKeyId? Key, IEnumerable<string> Values) Attributes, string? RightOperandValue)> GetPolicyContentAsync(UseCaseId? useCase, PolicyTypeId type, string credential) =>
_dbContext.Policies
dbContext.Policies
.Where(p =>
p.Types.Any(t => t.IsActive && t.Id == type) &&
(useCase == null || p.UseCases.Any(x => x.Id == useCase)) &&
Expand All @@ -68,7 +62,7 @@ public IAsyncEnumerable<PolicyTypeResponse> GetPolicyTypes(PolicyTypeId? type, U
.FirstOrDefaultAsync();

public IAsyncEnumerable<(string TechnicalKey, string LeftOperand, (AttributeKeyId? Key, IEnumerable<string> Values) Attributes, string? RightOperandValue)> GetPolicyForOperandContent(PolicyTypeId type, IEnumerable<string> technicalKeys) =>
_dbContext.Policies
dbContext.Policies
.Where(p =>
p.Types.Any(t => t.IsActive && t.Id == type) &&
technicalKeys.Contains(p.TechnicalKey))
Expand All @@ -79,4 +73,16 @@ public IAsyncEnumerable<PolicyTypeResponse> GetPolicyTypes(PolicyTypeId? type, U
p.PolicyKind!.Configuration!.RightOperandValue
))
.AsAsyncEnumerable();

public Task<List<(string TechnicalKey, AttributeKeyId? AttributeKey, IEnumerable<string> Values)>> GetAttributeValuesForTechnicalKeys(PolicyTypeId type, IEnumerable<string> technicalKeys) =>
dbContext.Policies
.Where(p =>
p.IsActive &&
p.Types.Any(t => t.IsActive && t.Id == type) &&
technicalKeys.Contains(p.TechnicalKey))
.Select(x => new ValueTuple<string, AttributeKeyId?, IEnumerable<string>>(
x.TechnicalKey,
x.AttributeKeyId,
x.Attributes.Select(a => a.AttributeValue)))
.ToListAsync();
}
28 changes: 2 additions & 26 deletions src/database/PolicyHub.Migrations/Seeder/Data/policies.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,7 @@
"description": "With the Framework Credential, only those participants which have signed the respective framework agreement (general or via a specific version) are allowed to view or negotiate the respective data offer. Generic: \"rightOperand\": \"active\"; specific \"rightOperand\": \"active:{version}\"",
"is_active": true,
"attribute_key_id": 5
},
{
"id": "01a0fba3-9b6e-435a-b045-e0e890c300b7",
"kind_id": 4,
"technical_key": "purpose.trace.v1.TraceBattery",
"description": "Facilitating compliance with mandatory regulatory requirements for tracking and reporting battery cells, modules & high-voltage batteries.",
"is_active": true,
"attribute_key_id": 2
},
{
"id": "01a0fba3-9b6e-435a-b045-e0e890c300b8",
"kind_id": 4,
"technical_key": "purpose.trace.v1.aspects",
"description": "Establishing a digital representation of the automotive supply chain to enable a component specific data exchange.",
"is_active": true,
"attribute_key_id": 2
},
{
"id": "01a0fba3-9b6e-435a-b045-e0e890c300b9",
"kind_id": 4,
"technical_key": "purpose.trace.v1.qualityanalysis",
"description": " The data can be used for quality analysis to identify and select affected components and to send quality notifications to affected customers or suppliers.",
"is_active": true,
"attribute_key_id": 2
},
},
{
"id": "01a0fba3-9b6e-435a-b045-e0e890c300c1",
"kind_id": 5,
Expand All @@ -86,6 +62,6 @@
"technical_key": "purpose",
"description": "",
"is_active": true,
"attribute_key_id": 3
"attribute_key_id": 2
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b4", "policy_type_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b5", "policy_type_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b6", "policy_type_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b7", "policy_type_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b8", "policy_type_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b9", "policy_type_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c1", "policy_type_id": 1, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c1", "policy_type_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c2", "policy_type_id": 2, "is_active": true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b4", "use_case_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b5", "use_case_id": 3, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b6", "use_case_id": 4, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b7", "use_case_id": 1, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b8", "use_case_id": 1, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b9", "use_case_id": 1, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c1", "use_case_id": 1, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c1", "use_case_id": 2, "is_active": true },
{ "policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c1", "use_case_id": 3, "is_active": true },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,19 @@
"is_active": true
},
{
"policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b7",
"policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c2",
"key": 2,
"attribute_value": "purpose.trace.v1.TraceBattery",
"is_active": true
},
{
"policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b8",
"policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c2",
"key": 2,
"attribute_value": "purpose.trace.v1.aspects",
"is_active": true
},
{
"policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300b9",
"policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c2",
"key": 2,
"attribute_value": "purpose.trace.v1.qualityanalysis",
"is_active": true
Expand All @@ -82,11 +82,5 @@
"key": 4,
"attribute_value": "VW",
"is_active": true
},
{
"policy_id": "01a0fba3-9b6e-435a-b045-e0e890c300c2",
"key": 2,
"attribute_value": "ID Trace 3.1",
"is_active": true
}
]
45 changes: 32 additions & 13 deletions src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,18 @@

namespace Org.Eclipse.TractusX.PolicyHub.Service.BusinessLogic;

public class PolicyHubBusinessLogic : IPolicyHubBusinessLogic
public class PolicyHubBusinessLogic(IHubRepositories hubRepositories)
: IPolicyHubBusinessLogic
{
private readonly IHubRepositories _hubRepositories;

public PolicyHubBusinessLogic(IHubRepositories hubRepositories)
{
_hubRepositories = hubRepositories;
}

public IAsyncEnumerable<string> GetAttributeKeys() =>
_hubRepositories.GetInstance<IPolicyRepository>().GetAttributeKeys();
hubRepositories.GetInstance<IPolicyRepository>().GetAttributeKeys();

public IAsyncEnumerable<PolicyTypeResponse> GetPolicyTypes(PolicyTypeId? type, UseCaseId? useCase) =>
_hubRepositories.GetInstance<IPolicyRepository>().GetPolicyTypes(type, useCase);
hubRepositories.GetInstance<IPolicyRepository>().GetPolicyTypes(type, useCase);

public async Task<PolicyResponse> GetPolicyContentWithFiltersAsync(UseCaseId? useCase, PolicyTypeId type, string credential, OperatorId operatorId, string? value)
{
var (exists, leftOperand, attributes, rightOperandValue) = await _hubRepositories.GetInstance<IPolicyRepository>().GetPolicyContentAsync(useCase, type, credential).ConfigureAwait(false);
var (exists, leftOperand, attributes, rightOperandValue) = await hubRepositories.GetInstance<IPolicyRepository>().GetPolicyContentAsync(useCase, type, credential).ConfigureAwait(false);
if (!exists)
{
throw new NotFoundException($"Policy for type {type} and technicalKey {credential} does not exists");
Expand Down Expand Up @@ -126,10 +120,35 @@ public async Task<PolicyResponse> GetPolicyContentAsync(PolicyContentRequest req
throw new ControllerArgumentException($"Keys {string.Join(",", multipleDefinedKey.Select(x => x.Key).Distinct())} have been defined multiple times");
}

var policies = await _hubRepositories.GetInstance<IPolicyRepository>().GetPolicyForOperandContent(requestData.PolicyType, requestData.Constraints.Select(x => x.Key)).ToListAsync().ConfigureAwait(false);
var technicalKeys = requestData.Constraints.Select(x => x.Key);
var attributeValuesForTechnicalKeys = await hubRepositories.GetInstance<IPolicyRepository>().GetAttributeValuesForTechnicalKeys(requestData.PolicyType, technicalKeys).ConfigureAwait(false);
if (technicalKeys.Except(attributeValuesForTechnicalKeys.Select(a => a.TechnicalKey)).Any())
{
throw new ControllerArgumentException($"Policy for type {requestData.PolicyType} and requested technicalKeys does not exists. TechnicalKeys {string.Join(",", attributeValuesForTechnicalKeys.Select(x => x.TechnicalKey))} are allowed");
}

IEnumerable<(string TechnicalKey, IEnumerable<string> Values)> keyValues = requestData.Constraints.GroupBy(x => x.Key).Select(x => new ValueTuple<string, IEnumerable<string>>(x.Key, x.Where(y => y.Value != null).Select(y => y.Value!)));
IEnumerable<(string TechnicalKey, IEnumerable<string> Values)> missingValues = keyValues
.Join(attributeValuesForTechnicalKeys, secondItem => secondItem.TechnicalKey, firstItem => firstItem.TechnicalKey,
(secondItem, firstItem) => new { secondItem, firstItem })
.Select(t => new { t, missing = t.secondItem.Values.Except(t.firstItem.Values) })
.Where(t => t.missing.Any())
.Select(t => (Key: t.t.secondItem.TechnicalKey, MissingValues: t.missing));

var attributesToIgnore = new[] { AttributeKeyId.Regex, AttributeKeyId.DynamicValue };
var technicalKeysToIgnore = attributeValuesForTechnicalKeys.Where(x => x.AttributeKey != null && attributesToIgnore.Any(y => y == x.AttributeKey)).Select(x => x.TechnicalKey);
var invalidValues = missingValues.Select(x => x.TechnicalKey).Except(technicalKeysToIgnore);
if (invalidValues.Any())
{
var x = missingValues.Where(x => invalidValues.Contains(x.TechnicalKey)).Select(x =>
$"Key: {x.TechnicalKey}, invalid values: {string.Join(',', x.Values)}");
throw new ControllerArgumentException($"Invalid values set for {string.Join(',', x)}");
}

var policies = await hubRepositories.GetInstance<IPolicyRepository>().GetPolicyForOperandContent(requestData.PolicyType, technicalKeys).ToListAsync().ConfigureAwait(false);
if (policies.Count != requestData.Constraints.Count())
{
throw new NotFoundException($"Policy for type {requestData.PolicyType} and technicalKeys {string.Join(",", requestData.Constraints.Select(x => x.Key).Except(policies.Select(x => x.TechnicalKey)))} does not exists");
throw new NotFoundException($"Policy for type {requestData.PolicyType} and technicalKeys {string.Join(",", technicalKeys.Except(policies.Select(x => x.TechnicalKey)))} does not exists");
}

var constraints = new List<Constraint>();
Expand Down
19 changes: 8 additions & 11 deletions tests/database/PolicyHub.DbAccess.Tests/PolicyRepositoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,14 @@ public async Task GetPolicyTypes_ReturnsExpectedResult()
var result = await sut.GetPolicyTypes(null, null).ToListAsync();

// Assert
result.Should().NotBeEmpty().And.HaveCount(11).And.Satisfy(
result.Should().NotBeEmpty().And.HaveCount(8).And.Satisfy(
x => x.TechnicalKey == "BusinessPartnerNumber",
x => x.TechnicalKey == "Membership",
x => x.TechnicalKey == "FrameworkAgreement.traceability",
x => x.TechnicalKey == "FrameworkAgreement.quality",
x => x.TechnicalKey == "FrameworkAgreement.pcf",
x => x.TechnicalKey == "FrameworkAgreement.behavioraltwin",
x => x.TechnicalKey == "purpose.trace.v1.TraceBattery",
x => x.TechnicalKey == "purpose.trace.v1.aspects",
x => x.TechnicalKey == "companyRole.dismantler",
x => x.TechnicalKey == "purpose.trace.v1.qualityanalysis",
x => x.TechnicalKey == "purpose"
);
}
Expand Down Expand Up @@ -132,14 +129,14 @@ public async Task GetPolicyContentAsync_WithoutRightOperand_ReturnsExpectedResul
var sut = await CreateSut();

// Act
var result = await sut.GetPolicyContentAsync(null, PolicyTypeId.Usage, "purpose.trace.v1.TraceBattery");
var result = await sut.GetPolicyContentAsync(null, PolicyTypeId.Usage, "Membership");

// Assert
result.Exists.Should().BeTrue();
result.Attributes.Key.Should().Be(AttributeKeyId.Static);
result.Attributes.Values.Should().ContainSingle()
.And.Satisfy(x => x == "purpose.trace.v1.TraceBattery");
result.LeftOperand.Should().Be("purpose.trace.v1.TraceBattery");
.And.Satisfy(x => x == "active");
result.LeftOperand.Should().Be("Membership");
result.RightOperandValue.Should().BeNull();
}

Expand Down Expand Up @@ -172,15 +169,15 @@ public async Task GetPolicyForOperandContent__ReturnsExpectedResult()
var sut = await CreateSut();

// Act
var result = await sut.GetPolicyForOperandContent(PolicyTypeId.Usage, Enumerable.Repeat("purpose.trace.v1.TraceBattery", 1)).ToListAsync();
var result = await sut.GetPolicyForOperandContent(PolicyTypeId.Usage, Enumerable.Repeat("Membership", 1)).ToListAsync();

// Assert
result.Should().ContainSingle()
.And.Satisfy(
x => x.TechnicalKey == "purpose.trace.v1.TraceBattery" &&
x => x.TechnicalKey == "Membership" &&
x.Attributes.Key == AttributeKeyId.Static &&
x.Attributes.Values.Single() == "purpose.trace.v1.TraceBattery" &&
x.LeftOperand == "purpose.trace.v1.TraceBattery" &&
x.Attributes.Values.Single() == "active" &&
x.LeftOperand == "Membership" &&
x.RightOperandValue == null);
}

Expand Down
Loading
Loading