From 097a914be279255ffde9e1d21f3d1286889a5618 Mon Sep 17 00:00:00 2001 From: leandro-cavalcante Date: Fri, 25 Oct 2024 15:01:37 +0200 Subject: [PATCH 1/4] Added fillter to enhance the error messages when query parameters are wrong or with incorrect value --- .../Controllers/PolicyHubController.cs | 18 ++- .../PolicyContentQueryParametersFilter.cs | 76 ++++++++++++ ...PolicyContentQueryParametersFilterTests.cs | 115 ++++++++++++++++++ 3 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs create mode 100644 tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs diff --git a/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs b/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs index 78a831c4..fc23fe74 100644 --- a/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs +++ b/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs @@ -22,6 +22,7 @@ using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; using Org.Eclipse.TractusX.PolicyHub.Service.BusinessLogic; using Org.Eclipse.TractusX.PolicyHub.Service.Extensions; +using Org.Eclipse.TractusX.PolicyHub.Service.Filters; using Org.Eclipse.TractusX.PolicyHub.Service.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Web; @@ -56,12 +57,21 @@ public static RouteGroupBuilder MapPolicyHubApi(this RouteGroupBuilder group) .Produces(StatusCodes.Status200OK, typeof(PolicyTypeResponse), Constants.JsonContentType); policyHub.MapGet("policy-content", - (UseCaseId? useCase, - PolicyTypeId type, + (string? useCase, + String type, string policyName, - OperatorId operatorType, + String operatorType, string? value, - IPolicyHubBusinessLogic logic) => logic.GetPolicyContentWithFiltersAsync(useCase, type, policyName, operatorType, value)) + IPolicyHubBusinessLogic logic) => + { + UseCaseId? useCaseId = null; + if (useCase != null && useCase.Trim() != string.Empty) + { + useCaseId = Enum.Parse(useCase, true); + } + return logic.GetPolicyContentWithFiltersAsync(useCaseId, Enum.Parse(type), policyName, Enum.Parse(operatorType), value); + }) + .AddEndpointFilter() .WithSwaggerDescription("Receive the policy template 'access' or 'usage' for a single policy rule based on the request parameters submitted by the user.", "Example: GET: api/policy-hub/policy-content", "OPTIONAL: The use case", diff --git a/src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs b/src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs new file mode 100644 index 00000000..13afd8b4 --- /dev/null +++ b/src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs @@ -0,0 +1,76 @@ +/******************************************************************************** + * Copyright (c) 2023 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 Org.Eclipse.TractusX.PolicyHub.Entities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Filters; + +public class PolicyContentQueryParametersFilter : IEndpointFilter +{ + public async ValueTask InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) + { + var queryParams = context.HttpContext.Request.Query; + var requiredParameters = new[] { "useCase", "type", "policyName", "operatorType", "value" }; + + // Validate query parameters + ValidateQueryParameters(queryParams, requiredParameters); + + // Validate enum parameters + ValidateEnumParameter(queryParams, "useCase"); + ValidateEnumParameter(queryParams, "type"); + ValidateEnumParameter(queryParams, "operatorType"); + + // Continue with the next filter or action + return await next(context); + } + + private static void ValidateQueryParameters(IQueryCollection queryParams, string[] requiredParameters) + { + var invalidParameters = queryParams + .Where(q => !requiredParameters.Contains(q.Key)) + .Select(q => q.Key) + .ToList(); + + if (invalidParameters.Any()) + { + throw new ControllerArgumentException($"Invalid query parameters: [{string.Join(", ", invalidParameters)}]. Accepted query parameters: [{string.Join(", ", requiredParameters)}]."); + } + } + + private static void ValidateEnumParameter(IQueryCollection queryParams, string paramName) where TEnum : struct, Enum + { + var paramValue = GetArgument(queryParams, paramName); + if (paramValue != null && !Enum.TryParse(paramValue, true, out _)) + { + ThrowIfInvalidEnumValue(paramValue, paramName); + } + } + + private static void ThrowIfInvalidEnumValue(string? value, string paramName) where TEnum : struct, Enum + { + var acceptedValues = string.Join(", ", Enum.GetNames()); + throw new ControllerArgumentException($"Invalid parameter value: [{paramName}: '{value}']. Accepted values: [{acceptedValues}]."); + } + + private static string? GetArgument(IQueryCollection queryParams, string argumentName) + { + return queryParams.TryGetValue(argumentName, out var value) ? value.ToString() : null; + } +} diff --git a/tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs b/tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs new file mode 100644 index 00000000..2a035403 --- /dev/null +++ b/tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs @@ -0,0 +1,115 @@ +/******************************************************************************** + * Copyright (c) 2023 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 + ********************************************************************************/ + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Tests.Filters; + +using FakeItEasy; +using Microsoft.AspNetCore.Http; +using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; +using Org.Eclipse.TractusX.PolicyHub.Service.Filters; +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +public class PolicyContentQueryParametersFilterTests +{ + [Fact] + public async Task InvokeAsync_ValidParameters_ContinuesToNext() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "useCase", UseCaseId.Quality.ToString() }, + { "type", PolicyTypeId.Access.ToString() }, + { "policyName", "UsagePurpose" }, + { "operatorType", OperatorId.Equals.ToString() }, + { "value", "testCalue" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + A.CallTo(() => next(A.Ignored)).Returns(ValueTask.FromResult(null)); + + var filter = new PolicyContentQueryParametersFilter(); + + // Act + var result = await filter.InvokeAsync(endpointContext, next); + + // Assert + A.CallTo(() => next(A.Ignored)).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task InvokeAsync_InvalidQueryParameter_ThrowsException() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "invalidParam", "InvalidValue" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + + var filter = new PolicyContentQueryParametersFilter(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); + Assert.Contains("Invalid query parameters", exception.Message); + } + + [Fact] + public async Task InvokeAsync_InvalidEnumParameter_ThrowsException() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "useCase", "InvalidUseCase" }, + { "type", "ValidType" }, + { "policyName", "ValidPolicyName" }, + { "operatorType", "ValidOperatorType" }, + { "value", "ValidValue" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + + var filter = new PolicyContentQueryParametersFilter(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); + Assert.Contains("Invalid parameter value: [useCase: 'InvalidUseCase']", exception.Message); + } +} From f899f23ef869b9b1358ac01593051bd1bf75f023 Mon Sep 17 00:00:00 2001 From: leandro-cavalcante <162341380+leandro-cavalcante@users.noreply.github.com> Date: Tue, 25 Feb 2025 11:50:17 +0100 Subject: [PATCH 2/4] feat: cs 2221 respond 4xx when parameters are unrecognised (#48) Co-authored-by: Arnab Kumar Nandy (Cofinity-X) <150015794+arnabcx@users.noreply.github.com> Co-authored-by: Nitesh Sakhiya <37956326+niteshsakhiya@users.noreply.github.com> --- docs/api/hub-service.yaml | 13 +- .../BusinessLogic/PolicyHubBusinessLogic.cs | 24 ++- .../Controllers/PolicyHubController.cs | 18 +- .../Filters/BaseQueryParametersFilter.cs | 93 ++++++++++ .../Filters/ParamEnumHelper.cs | 33 ++++ .../Filters/ParamEnumValidator.cs | 34 ++++ .../PolicyContentQueryParametersFilter.cs | 58 +------ .../PolicyTypesQueryParametersFilter.cs | 33 ++++ .../Filters/QueryParameterType.cs | 48 ++++++ .../PolicyHubBusinessLogicTests.cs | 24 ++- .../Controllers/PolicyHubControllerTests.cs | 15 ++ ...PolicyContentQueryParametersFilterTests.cs | 90 ++++++++-- .../PolicyTypesQueryParametersFilterTests.cs | 162 ++++++++++++++++++ 13 files changed, 553 insertions(+), 92 deletions(-) create mode 100644 src/hub/PolicyHub.Service/Filters/BaseQueryParametersFilter.cs create mode 100644 src/hub/PolicyHub.Service/Filters/ParamEnumHelper.cs create mode 100644 src/hub/PolicyHub.Service/Filters/ParamEnumValidator.cs create mode 100644 src/hub/PolicyHub.Service/Filters/PolicyTypesQueryParametersFilter.cs create mode 100644 src/hub/PolicyHub.Service/Filters/QueryParameterType.cs create mode 100644 tests/hub/PolicyHub.Service.Tests/Filters/PolicyTypesQueryParametersFilterTests.cs diff --git a/docs/api/hub-service.yaml b/docs/api/hub-service.yaml index 6abdc0ba..ea2fd62e 100644 --- a/docs/api/hub-service.yaml +++ b/docs/api/hub-service.yaml @@ -39,12 +39,12 @@ paths: in: query description: 'OPTIONAL: Type to filter the response' schema: - $ref: '#/components/schemas/PolicyTypeId' + type: string - name: useCase in: query description: 'OPTIONAL: UseCase to filter the response' schema: - $ref: '#/components/schemas/UseCaseId' + type: string responses: '200': description: OK @@ -75,25 +75,22 @@ paths: in: query description: 'OPTIONAL: The use case' schema: - $ref: '#/components/schemas/UseCaseId' + type: string - name: type in: query description: 'Policy type for which the policy is supposed to get created. Possible values: ''Access'' or ''Usage''' - required: true schema: - $ref: '#/components/schemas/PolicyTypeId' + type: string - name: policyName in: query description: The technical key of the policy - required: true schema: type: string - name: operatorType in: query description: 'Policy Rule operator. Possible values: ''Equals'' or ''In''' - required: true schema: - $ref: '#/components/schemas/OperatorId' + type: string - name: value in: query description: 'OPTIONAL: Value to be used for the rightOperand' diff --git a/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs b/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs index 9c3d5001..db5cb0af 100644 --- a/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs +++ b/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs @@ -65,10 +65,30 @@ private static (object rightOperand, AdditionalAttributes? additionalAttribute) AttributeKeyId.DynamicValue => (value ?? "{dynamicValue}", null), AttributeKeyId.Regex => (GetRegexValue(attributes, value), null), _ => operatorId == OperatorId.Equals - ? ProcessEqualsOperator(attributes, rightOperands, value, leftOperand, useCase) + ? processEqualsOperator(attributes, rightOperands, value, leftOperand, useCase) : (rightOperands, null) }; + private static (object rightOperand, AdditionalAttributes? additionalAttribute) processEqualsOperator((AttributeKeyId? Key, IEnumerable Values) attributes, IEnumerable rightOperands, string? value, string leftOperand, UseCaseId? useCase) + { + if (value != null) + { + if (!rightOperands.Any(r => r == value)) + { + throw new ControllerArgumentException($"Invalid values [{value}] set for key {leftOperand}. Possible values [{string.Join(",", rightOperands)}]"); + } + rightOperands = rightOperands.Where(r => r.Equals(value)); + } + return rightOperands.Count() > 1 ? + ($"@{leftOperand}{(useCase != null ? + useCase.Value.ToString().Insert(0, ".") : + string.Empty)}-{attributes.Key}", + new AdditionalAttributes($"@{leftOperand}{(useCase != null ? + useCase.Value.ToString().Insert(0, ".") : + string.Empty)}-{attributes.Key}", rightOperands)) : + (rightOperands.Single(), null); + } + private static (object rightOperand, AdditionalAttributes? additionalAttribute) ProcessEqualsOperator((AttributeKeyId? Key, IEnumerable Values) attributes, IEnumerable rightOperands, string? value, string leftOperand, UseCaseId? useCase) { if (value != null) @@ -180,7 +200,7 @@ public async Task GetPolicyContentAsync(PolicyContentRequest req { var x = missingValues.Where(x => invalidValues.Contains(x.TechnicalKey)).Select(x => $"Key: {x.TechnicalKey}, requested value[{string.Join(',', x.Values)}] Possible Values[{string.Join(',', attributeValuesForTechnicalKeys.Where(a => a.TechnicalKey.Equals(x.TechnicalKey)).Select(a => a.Values).First())}]"); - throw ControllerArgumentException.Create(PolicyErrors.INVALID_VALUES_SET, new ErrorParameter[] { new("values", string.Join(',', x)) }); + throw new ControllerArgumentException($"Invalid values set for {string.Join(',', x)}"); } var policies = await hubRepositories.GetInstance().GetPolicyForOperandContent(requestData.PolicyType, technicalKeys).ToListAsync().ConfigureAwait(false); diff --git a/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs b/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs index fc23fe74..f59a27dd 100644 --- a/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs +++ b/src/hub/PolicyHub.Service/Controllers/PolicyHubController.cs @@ -47,7 +47,9 @@ public static RouteGroupBuilder MapPolicyHubApi(this RouteGroupBuilder group) .WithDefaultResponses() .Produces(StatusCodes.Status200OK, typeof(string), Constants.JsonContentType); - policyHub.MapGet("policy-types", (PolicyTypeId? type, UseCaseId? useCase, IPolicyHubBusinessLogic logic) => logic.GetPolicyTypes(type, useCase)) + policyHub.MapGet("policy-types", (string? type, string? useCase, IPolicyHubBusinessLogic logic) => + logic.GetPolicyTypes(ParamEnumHelper.ParseEnum(type), ParamEnumHelper.ParseEnum(useCase))) + .AddEndpointFilter() .WithSwaggerDescription("Provides all current supported policy types incl. a policy description and useCase link.", "Example: GET: api/policy-hub/policy-types", "OPTIONAL: Type to filter the response", @@ -58,18 +60,18 @@ public static RouteGroupBuilder MapPolicyHubApi(this RouteGroupBuilder group) policyHub.MapGet("policy-content", (string? useCase, - String type, - string policyName, - String operatorType, + String? type, + string? policyName, + String? operatorType, string? value, IPolicyHubBusinessLogic logic) => { - UseCaseId? useCaseId = null; - if (useCase != null && useCase.Trim() != string.Empty) + if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(policyName) || string.IsNullOrEmpty(operatorType)) { - useCaseId = Enum.Parse(useCase, true); + throw new ArgumentNullException(nameof(type), "Type parameter cannot be null or empty."); } - return logic.GetPolicyContentWithFiltersAsync(useCaseId, Enum.Parse(type), policyName, Enum.Parse(operatorType), value); + + return logic.GetPolicyContentWithFiltersAsync(ParamEnumHelper.ParseEnum(useCase), Enum.Parse(type), policyName, Enum.Parse(operatorType), value); }) .AddEndpointFilter() .WithSwaggerDescription("Receive the policy template 'access' or 'usage' for a single policy rule based on the request parameters submitted by the user.", diff --git a/src/hub/PolicyHub.Service/Filters/BaseQueryParametersFilter.cs b/src/hub/PolicyHub.Service/Filters/BaseQueryParametersFilter.cs new file mode 100644 index 00000000..bbf69b68 --- /dev/null +++ b/src/hub/PolicyHub.Service/Filters/BaseQueryParametersFilter.cs @@ -0,0 +1,93 @@ +/******************************************************************************** + * Copyright (c) 2025 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 Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Filters; + +public abstract class BaseQueryParametersFilter : IEndpointFilter +{ + protected readonly Dictionary _queryParameters; + + protected BaseQueryParametersFilter(Dictionary queryParameters) + { + _queryParameters = queryParameters; + } + + public async ValueTask InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) + { + var queryParams = context.HttpContext.Request.Query; + + // Check for required parameters + EnsureRequiredParameters(queryParams); + + // Validate supported query parameters + ValidateSupportedQueryParameters(queryParams); + + // Validate enum parameter values + ValidateEnumParameters(queryParams); + + // Continue with the next filter or action + return await next(context); + } + + private void EnsureRequiredParameters(IQueryCollection queryParams) + { + var missingRequiredParameters = _queryParameters + .Where(q => q.Value.IsRequired && GetArgument(queryParams, q.Key) == null) + .Select(q => q.Key) + .ToList(); + + if (missingRequiredParameters.Count != 0) + { + throw new NotFoundException($"Missing required parameters: {string.Join(", ", missingRequiredParameters)}."); + } + } + + private void ValidateSupportedQueryParameters(IQueryCollection queryParams) + { + var invalidParameters = queryParams + .Where(q => !_queryParameters.ContainsKey(q.Key)) + .Select(q => $"{q.Key}") + .ToList(); + + if (invalidParameters.Count != 0) + { + throw new ControllerArgumentException($"Invalid query parameters: {string.Join(", ", invalidParameters)}. Supported parameters are: {string.Join(", ", _queryParameters.Keys)}."); + } + } + + private void ValidateEnumParameters(IQueryCollection queryParams) + { + foreach (var param in _queryParameters) + { + var paramValue = GetArgument(queryParams, param.Key); + if (paramValue != null && param.Value.EnumType != null) + { + ParamEnumValidator.ThrowIfInvalidEnumValue(param.Value.EnumType, paramValue, param.Key); + } + } + } + + protected static string? GetArgument(IQueryCollection queryParams, string argumentName) + { + return queryParams.TryGetValue(argumentName, out var value) ? value.ToString() : null; + } +} + diff --git a/src/hub/PolicyHub.Service/Filters/ParamEnumHelper.cs b/src/hub/PolicyHub.Service/Filters/ParamEnumHelper.cs new file mode 100644 index 00000000..8000f437 --- /dev/null +++ b/src/hub/PolicyHub.Service/Filters/ParamEnumHelper.cs @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2025 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 + ********************************************************************************/ + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Filters; + +public static class ParamEnumHelper +{ + public static TEnum? ParseEnum(string? value) where TEnum : struct, Enum + { + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + + return Enum.Parse(value.Trim(), true); + } +} diff --git a/src/hub/PolicyHub.Service/Filters/ParamEnumValidator.cs b/src/hub/PolicyHub.Service/Filters/ParamEnumValidator.cs new file mode 100644 index 00000000..aff80201 --- /dev/null +++ b/src/hub/PolicyHub.Service/Filters/ParamEnumValidator.cs @@ -0,0 +1,34 @@ +/******************************************************************************** + * Copyright (c) 2025 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 Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Filters; + +public static class ParamEnumValidator +{ + public static void ThrowIfInvalidEnumValue(Type enumType, string value, string paramName) + { + if (!Enum.IsDefined(enumType, value)) + { + var acceptedValues = string.Join(", ", Enum.GetNames(enumType)); + throw new ControllerArgumentException($"Invalid value '{value}' for parameter '{paramName}'. Accepted values are: {acceptedValues}."); + } + } +} diff --git a/src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs b/src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs index 13afd8b4..8bb073b6 100644 --- a/src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs +++ b/src/hub/PolicyHub.Service/Filters/PolicyContentQueryParametersFilter.cs @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation + * Copyright (c) 2025 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -18,59 +18,19 @@ ********************************************************************************/ using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; namespace Org.Eclipse.TractusX.PolicyHub.Service.Filters; -public class PolicyContentQueryParametersFilter : IEndpointFilter +public class PolicyContentQueryParametersFilter : BaseQueryParametersFilter { - public async ValueTask InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) + public PolicyContentQueryParametersFilter() : base(new Dictionary { - var queryParams = context.HttpContext.Request.Query; - var requiredParameters = new[] { "useCase", "type", "policyName", "operatorType", "value" }; - - // Validate query parameters - ValidateQueryParameters(queryParams, requiredParameters); - - // Validate enum parameters - ValidateEnumParameter(queryParams, "useCase"); - ValidateEnumParameter(queryParams, "type"); - ValidateEnumParameter(queryParams, "operatorType"); - - // Continue with the next filter or action - return await next(context); - } - - private static void ValidateQueryParameters(IQueryCollection queryParams, string[] requiredParameters) - { - var invalidParameters = queryParams - .Where(q => !requiredParameters.Contains(q.Key)) - .Select(q => q.Key) - .ToList(); - - if (invalidParameters.Any()) - { - throw new ControllerArgumentException($"Invalid query parameters: [{string.Join(", ", invalidParameters)}]. Accepted query parameters: [{string.Join(", ", requiredParameters)}]."); - } - } - - private static void ValidateEnumParameter(IQueryCollection queryParams, string paramName) where TEnum : struct, Enum - { - var paramValue = GetArgument(queryParams, paramName); - if (paramValue != null && !Enum.TryParse(paramValue, true, out _)) - { - ThrowIfInvalidEnumValue(paramValue, paramName); - } - } - - private static void ThrowIfInvalidEnumValue(string? value, string paramName) where TEnum : struct, Enum - { - var acceptedValues = string.Join(", ", Enum.GetNames()); - throw new ControllerArgumentException($"Invalid parameter value: [{paramName}: '{value}']. Accepted values: [{acceptedValues}]."); - } - - private static string? GetArgument(IQueryCollection queryParams, string argumentName) + { "useCase", new QueryParameterType { IsRequired = false, EnumType = typeof(UseCaseId) } }, + { "type", new QueryParameterType { IsRequired = true, EnumType = typeof(PolicyTypeId) } }, + { "policyName", new QueryParameterType { IsRequired = true } }, + { "operatorType", new QueryParameterType { IsRequired = true, EnumType = typeof(OperatorId) } }, + { "value", new QueryParameterType { IsRequired = false } } + }) { - return queryParams.TryGetValue(argumentName, out var value) ? value.ToString() : null; } } diff --git a/src/hub/PolicyHub.Service/Filters/PolicyTypesQueryParametersFilter.cs b/src/hub/PolicyHub.Service/Filters/PolicyTypesQueryParametersFilter.cs new file mode 100644 index 00000000..1713bf2f --- /dev/null +++ b/src/hub/PolicyHub.Service/Filters/PolicyTypesQueryParametersFilter.cs @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2025 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 Org.Eclipse.TractusX.PolicyHub.Entities.Enums; + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Filters; + +public class PolicyTypesQueryParametersFilter : BaseQueryParametersFilter +{ + public PolicyTypesQueryParametersFilter() : base(new Dictionary + { + { "useCase", new QueryParameterType { IsRequired = false, EnumType = typeof(UseCaseId) } }, + { "type", new QueryParameterType { IsRequired = false, EnumType = typeof(PolicyTypeId) } } + }) + { + } +} diff --git a/src/hub/PolicyHub.Service/Filters/QueryParameterType.cs b/src/hub/PolicyHub.Service/Filters/QueryParameterType.cs new file mode 100644 index 00000000..ce61cd9c --- /dev/null +++ b/src/hub/PolicyHub.Service/Filters/QueryParameterType.cs @@ -0,0 +1,48 @@ +/******************************************************************************** + * Copyright (c) 2025 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 + ********************************************************************************/ + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Filters; + +public class QueryParameterType +{ + public bool IsRequired { get; set; } + public Type? EnumType { get; set; } + private object? _enumValue; + + public object? EnumValue + { + get => _enumValue; + set + { + if (value is Enum) + { + _enumValue = value; + } + else + { + throw new ArgumentException("Value must be an enum type."); + } + } + } + + public void SetEnumValue(TEnum value) where TEnum : struct, Enum + { + EnumValue = value; + } +} diff --git a/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs b/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs index 47f25270..9be4d76b 100644 --- a/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs +++ b/tests/hub/PolicyHub.Service.Tests/BusinessLogic/PolicyHubBusinessLogicTests.cs @@ -194,7 +194,7 @@ public async Task GetPolicyContentWithFiltersAsync_WithInvalidValue_ExceptionExp { // Arrange A.CallTo(() => _policyRepository.GetPolicyContentAsync(UseCaseId.Traceability, PolicyTypeId.Usage, "multipleAdditionalValues")) - .Returns(new ValueTuple>, string?>(true, "multipleAdditionalValues", new ValueTuple>(AttributeKeyId.Static, new[] { "value1", "value2", "value3" }), null)); + .Returns(new ValueTuple>, string?>(true, "multipleAdditionalValues", new ValueTuple>(AttributeKeyId.Static, ["value1", "value2", "value3"]), null)); // Act async Task Act() => await _sut.GetPolicyContentWithFiltersAsync(UseCaseId.Traceability, PolicyTypeId.Usage, "multipleAdditionalValues", OperatorId.Equals, "test"); @@ -203,7 +203,7 @@ public async Task GetPolicyContentWithFiltersAsync_WithInvalidValue_ExceptionExp var ex = await Assert.ThrowsAsync(Act); // Assert - ex.Message.Should().Be(PolicyErrors.INVALID_VALUES.ToString()); + ex.Message.Should().Be("Invalid values [test] set for key multipleAdditionalValues. Possible values [value1,value2,value3]"); } #endregion @@ -263,26 +263,34 @@ public async Task GetPolicyContentAsync_WithUnmatchingTechnicalKeys_ThrowsContro public async Task GetPolicyContentAsync_WithUnmatchingAttributeValues_ThrowsControllerArgumentException() { // Arrange + List<(string TechnicalKey, AttributeKeyId? AttributeKey, IEnumerable Values)> possibleValues = [ + ("test", AttributeKeyId.Version, ["test"]), + ("abc", AttributeKeyId.Version, []) + ]; + var data = new PolicyContentRequest(PolicyTypeId.Access, ConstraintOperandId.Or, new[] { new Constraints("test", OperatorId.In, "abc"), new Constraints("abc", OperatorId.Equals, null) }); + + var technicalKey = "test"; + var attributeId = "1234"; + + var policyForOperand = new ValueTuple>, string?>(technicalKey, attributeId, default, null); + A.CallTo(() => _policyRepository.GetAttributeValuesForTechnicalKeys(data.PolicyType, A>._)) - .Returns([ - ("test", AttributeKeyId.Version, ["test"]), - ("abc", AttributeKeyId.Version, []) - ]); + .Returns(possibleValues); A.CallTo(() => _policyRepository.GetPolicyForOperandContent(data.PolicyType, A>._)) - .Returns(Enumerable.Repeat(new ValueTuple>, string?>("test", "active", default, null), 1).ToAsyncEnumerable()); + .Returns(Enumerable.Repeat(policyForOperand, 1).ToAsyncEnumerable()); async Task Act() => await _sut.GetPolicyContentAsync(data); // Act var ex = await Assert.ThrowsAsync(Act); // Assert - ex.Message.Should().Be(PolicyErrors.INVALID_VALUES_SET.ToString()); + ex.Message.Should().Be("Invalid values set for Key: test, requested value[abc] Possible Values[test]"); } [Fact] diff --git a/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs b/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs index 5ff68a11..eb847278 100644 --- a/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs +++ b/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs @@ -276,4 +276,19 @@ public async Task GetPolicyContentWithFiltersAsync_MultipleConstraintsEqualsAndO } #endregion + + #region Swagger + + [Fact] + public async Task CheckSwagger_ReturnsExpected() + { + // Act + var response = await _client.GetAsync($"{BaseUrl}/swagger/v2/swagger.json"); + + // Assert + response.Should().NotBeNull(); + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + + #endregion } diff --git a/tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs b/tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs index 2a035403..f584ab79 100644 --- a/tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs +++ b/tests/hub/PolicyHub.Service.Tests/Filters/PolicyContentQueryParametersFilterTests.cs @@ -21,7 +21,7 @@ namespace Org.Eclipse.TractusX.PolicyHub.Service.Tests.Filters; using FakeItEasy; using Microsoft.AspNetCore.Http; -using Org.Eclipse.TractusX.PolicyHub.Entities.Enums; +using Microsoft.Extensions.Primitives; using Org.Eclipse.TractusX.PolicyHub.Service.Filters; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using System.Collections.Generic; @@ -34,13 +34,13 @@ public class PolicyContentQueryParametersFilterTests public async Task InvokeAsync_ValidParameters_ContinuesToNext() { // Arrange - var queryParams = new QueryCollection(new Dictionary + var queryParams = new QueryCollection(new Dictionary { - { "useCase", UseCaseId.Quality.ToString() }, - { "type", PolicyTypeId.Access.ToString() }, - { "policyName", "UsagePurpose" }, - { "operatorType", OperatorId.Equals.ToString() }, - { "value", "testCalue" } + { "useCase", "PCF" }, + { "type", "Usage" }, + { "policyName", "ValidPolicyName" }, + { "operatorType", "Equals" }, + { "value", "ValidValue" } }); var context = new DefaultHttpContext(); @@ -50,22 +50,22 @@ public async Task InvokeAsync_ValidParameters_ContinuesToNext() A.CallTo(() => endpointContext.HttpContext).Returns(context); var next = A.Fake(); - A.CallTo(() => next(A.Ignored)).Returns(ValueTask.FromResult(null)); + A.CallTo(() => next(A.Ignored)).Returns(ValueTask.FromResult(null).AsTask()); var filter = new PolicyContentQueryParametersFilter(); // Act - var result = await filter.InvokeAsync(endpointContext, next); + await filter.InvokeAsync(endpointContext, next); // Assert A.CallTo(() => next(A.Ignored)).MustHaveHappenedOnceExactly(); } [Fact] - public async Task InvokeAsync_InvalidQueryParameter_ThrowsException() + public async Task InvokeAsync_Missing_And_InvalidQueryParameter_ThrowsException() { // Arrange - var queryParams = new QueryCollection(new Dictionary + var queryParams = new QueryCollection(new Dictionary { { "invalidParam", "InvalidValue" } }); @@ -80,22 +80,51 @@ public async Task InvokeAsync_InvalidQueryParameter_ThrowsException() var filter = new PolicyContentQueryParametersFilter(); + // Act & Assert + var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); + Assert.Equal("Missing required parameters: type, policyName, operatorType.", exception.Message); + } + + [Fact] + public async Task InvokeAsync_InvalidQueryParameters_ThrowsException() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "useCase", "PCF" }, + { "type", "Usage" }, + { "policyName", "ValidPolicyName" }, + { "operatorType", "Equals" }, + { "value", "ValidValue" }, + { "invalidParam1", "InvalidValue1" }, + { "invalidParam2", "InvalidValue2" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + + var filter = new PolicyContentQueryParametersFilter(); + // Act & Assert var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); - Assert.Contains("Invalid query parameters", exception.Message); + Assert.Equal("Invalid query parameters: invalidParam1, invalidParam2. Supported parameters are: useCase, type, policyName, operatorType, value.", exception.Message); } [Fact] public async Task InvokeAsync_InvalidEnumParameter_ThrowsException() { // Arrange - var queryParams = new QueryCollection(new Dictionary + var queryParams = new QueryCollection(new Dictionary { { "useCase", "InvalidUseCase" }, - { "type", "ValidType" }, + { "type", "Usage" }, { "policyName", "ValidPolicyName" }, - { "operatorType", "ValidOperatorType" }, - { "value", "ValidValue" } + { "operatorType", "Equals" }, }); var context = new DefaultHttpContext(); @@ -110,6 +139,33 @@ public async Task InvokeAsync_InvalidEnumParameter_ThrowsException() // Act & Assert var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); - Assert.Contains("Invalid parameter value: [useCase: 'InvalidUseCase']", exception.Message); + Assert.Equal("Invalid value 'InvalidUseCase' for parameter 'useCase'. Accepted values are: Traceability, Quality, PCF, Behavioraltwin, Businesspartner, CircularEconomy, DemandCapacity.", exception.Message); + } + + [Fact] + public async Task InvokeAsync_MissingRequiredParameter_ThrowsException() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "useCase", "PCF" }, + { "policyName", "ValidPolicyName" }, + { "operatorType", "Equals" }, + { "value", "ValidValue" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + + var filter = new PolicyContentQueryParametersFilter(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); + Assert.Contains("Missing required parameters: type.", exception.Message); } } diff --git a/tests/hub/PolicyHub.Service.Tests/Filters/PolicyTypesQueryParametersFilterTests.cs b/tests/hub/PolicyHub.Service.Tests/Filters/PolicyTypesQueryParametersFilterTests.cs new file mode 100644 index 00000000..021eeca8 --- /dev/null +++ b/tests/hub/PolicyHub.Service.Tests/Filters/PolicyTypesQueryParametersFilterTests.cs @@ -0,0 +1,162 @@ +/******************************************************************************** + * Copyright (c) 2025 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 + ********************************************************************************/ + +namespace Org.Eclipse.TractusX.PolicyHub.Service.Tests.Filters; + +using FakeItEasy; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using Org.Eclipse.TractusX.PolicyHub.Service.Filters; +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +public class PolicyTypesQueryParametersFilterTests +{ + [Fact] + public async Task InvokeAsync_ValidParameters_ContinuesToNext() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "useCase", "PCF" }, + { "type", "Usage" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + A.CallTo(() => next(A.Ignored)).Returns(ValueTask.FromResult(null).AsTask()); + + var filter = new PolicyTypesQueryParametersFilter(); + + // Act + await filter.InvokeAsync(endpointContext, next); + + // Assert + A.CallTo(() => next(A.Ignored)).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task InvokeAsync_NoParametersProvided_ContinuesToNext() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + A.CallTo(() => next(A.Ignored)).Returns(ValueTask.FromResult(null).AsTask()); + + var filter = new PolicyTypesQueryParametersFilter(); + + // Act + await filter.InvokeAsync(endpointContext, next); + + // Assert + A.CallTo(() => next(A.Ignored)).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task InvokeAsync_Missing_And_InvalidQueryParameter_ThrowsException() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "invalidParam", "InvalidValue" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + + var filter = new PolicyTypesQueryParametersFilter(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); + Assert.Equal("Invalid query parameters: invalidParam. Supported parameters are: useCase, type.", exception.Message); + } + + [Fact] + public async Task InvokeAsync_InvalidQueryParameters_ThrowsException() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "useCase", "PCF" }, + { "type", "Usage" }, + { "invalidParam1", "InvalidValue1" }, + { "invalidParam2", "InvalidValue2" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + + var filter = new PolicyTypesQueryParametersFilter(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); + Assert.Equal("Invalid query parameters: invalidParam1, invalidParam2. Supported parameters are: useCase, type.", exception.Message); + } + + [Fact] + public async Task InvokeAsync_InvalidEnumParameter_ThrowsException() + { + // Arrange + var queryParams = new QueryCollection(new Dictionary + { + { "useCase", "InvalidUseCase" }, + { "type", "Usage" } + }); + + var context = new DefaultHttpContext(); + context.Request.Query = queryParams; + + var endpointContext = A.Fake(); + A.CallTo(() => endpointContext.HttpContext).Returns(context); + + var next = A.Fake(); + + var filter = new PolicyTypesQueryParametersFilter(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => filter.InvokeAsync(endpointContext, next).AsTask()); + Assert.Equal("Invalid value 'InvalidUseCase' for parameter 'useCase'. Accepted values are: Traceability, Quality, PCF, Behavioraltwin, Businesspartner, CircularEconomy, DemandCapacity.", exception.Message); + } +} From 7eef4ddb7650ce32ba562971c546efc144204ffa Mon Sep 17 00:00:00 2001 From: leandro-cavalcante Date: Tue, 15 Apr 2025 16:10:33 +0200 Subject: [PATCH 3/4] removed unecessary test --- .../Controllers/PolicyHubControllerTests.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs b/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs index eb847278..5ff68a11 100644 --- a/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs +++ b/tests/hub/PolicyHub.Service.Tests/Controllers/PolicyHubControllerTests.cs @@ -276,19 +276,4 @@ public async Task GetPolicyContentWithFiltersAsync_MultipleConstraintsEqualsAndO } #endregion - - #region Swagger - - [Fact] - public async Task CheckSwagger_ReturnsExpected() - { - // Act - var response = await _client.GetAsync($"{BaseUrl}/swagger/v2/swagger.json"); - - // Assert - response.Should().NotBeNull(); - response.StatusCode.Should().Be(HttpStatusCode.OK); - } - - #endregion } From 6fa4fab603ddaf1bab8cc10b42be9487cc762d2c Mon Sep 17 00:00:00 2001 From: leandro-cavalcante Date: Tue, 15 Apr 2025 16:48:23 +0200 Subject: [PATCH 4/4] Fixed the format of the file --- .../BusinessLogic/PolicyHubBusinessLogic.cs | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs b/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs index db5cb0af..70cc0027 100644 --- a/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs +++ b/src/hub/PolicyHub.Service/BusinessLogic/PolicyHubBusinessLogic.cs @@ -89,27 +89,6 @@ private static (object rightOperand, AdditionalAttributes? additionalAttribute) (rightOperands.Single(), null); } - private static (object rightOperand, AdditionalAttributes? additionalAttribute) ProcessEqualsOperator((AttributeKeyId? Key, IEnumerable Values) attributes, IEnumerable rightOperands, string? value, string leftOperand, UseCaseId? useCase) - { - if (value != null) - { - if (!rightOperands.Any(r => r == value)) - { - throw ControllerArgumentException.Create(PolicyErrors.INVALID_VALUES, new ErrorParameter[] { new("value", value), new("leftOperand", leftOperand), new("possibleValues", string.Join(",", rightOperands)) }); - } - - rightOperands = rightOperands.Where(r => r.Equals(value)); - } - - var useCaseValue = useCase != null ? - useCase.Value.ToString().Insert(0, ".") : - string.Empty; - var rightOperand = $"@{leftOperand}{useCaseValue}-{attributes.Key}"; - return rightOperands.Count() > 1 ? - (rightOperand, new AdditionalAttributes(rightOperand, rightOperands)) : - (rightOperands.Single(), null); - } - private static object GetRegexValue((AttributeKeyId? Key, IEnumerable Values) attributes, string? value) { if (string.IsNullOrWhiteSpace(value))