From 1ef5b81cb9aa5f7b216719a110028293dcf4c63e Mon Sep 17 00:00:00 2001 From: Tristan Chuine Date: Thu, 2 Oct 2025 09:47:20 +0200 Subject: [PATCH 1/9] Add new ednpoint --- pom.xml | 7 ++- .../server/controller/StudyController.java | 17 ++++++++ .../study/server/service/FilterService.java | 43 ++++++++++++++----- .../study/server/service/StudyService.java | 21 +++++++++ 4 files changed, 76 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 5867adc3c2..d1572d9ac2 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 43.0.0 org.gridsuite.study.server 5.0.0-alpha.14 - 1.0.5 + 1.0.5 gridsuite org.gridsuite:study-server @@ -144,6 +144,11 @@ com.powsybl powsybl-ws-commons + + org.gridsuite + gridsuite-filter + 1.10.0-SNAPSHOT + io.projectreactor reactor-core diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index c45cf2aa39..28d4b90302 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -16,6 +16,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; +import org.gridsuite.filter.globalfilter.GlobalFilter; +import org.gridsuite.filter.utils.EquipmentType; import org.gridsuite.study.server.StudyApi; import org.gridsuite.study.server.StudyException; import org.gridsuite.study.server.StudyException.Type; @@ -53,6 +55,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; @@ -2344,6 +2347,20 @@ public ResponseEntity evaluateFilter( return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(studyService.evaluateFilter(nodeUuid, rootNetworkUuid, inUpstreamBuiltParentNode, filter)); } + @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/global-filter/evaluate", + produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Evaluate a filter to get matched elements") + @ApiResponse(responseCode = "200", description = "The list of matched elements") + public ResponseEntity> evaluateGlobalFilter( + @Parameter(description = "Study uuid") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "Root network uuid") @PathVariable("rootNetworkUuid") UUID rootNetworkUuid, + @Parameter(description = "Node uuid") @PathVariable("nodeUuid") UUID nodeUuid, + @Parameter(description = "The equipments types to filter and return") @RequestParam(name = "equipmentTypes") @NonNull final List equipmentTypes, + @RequestBody @NonNull GlobalFilter filter) { + this.studyService.assertIsRootNetworkAndNodeInStudy(studyUuid, rootNetworkUuid, nodeUuid); + return ResponseEntity.ok(studyService.evaluateGlobalFilter(nodeUuid, rootNetworkUuid, equipmentTypes, filter)); + } + @GetMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/filters/{filterUuid}/elements") @Operation(summary = "Evaluate a filter on root node to get matched elements") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The list of matched elements")}) diff --git a/src/main/java/org/gridsuite/study/server/service/FilterService.java b/src/main/java/org/gridsuite/study/server/service/FilterService.java index 064bdfb128..47422e09fe 100644 --- a/src/main/java/org/gridsuite/study/server/service/FilterService.java +++ b/src/main/java/org/gridsuite/study/server/service/FilterService.java @@ -7,16 +7,20 @@ package org.gridsuite.study.server.service; +import lombok.Getter; +import lombok.NonNull; +import org.gridsuite.filter.globalfilter.GlobalFilter; +import org.gridsuite.filter.utils.EquipmentType; import org.gridsuite.study.server.RemoteServicesProperties; import org.gridsuite.study.server.StudyException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.ResolvableType; +import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import java.util.List; @@ -42,13 +46,9 @@ public class FilterService { private final RestTemplate restTemplate; + @Getter // getter to facilitate to mock private final String baseUri; - // getter to facilitate to mock - public String getBaseUri() { - return baseUri; - } - @Autowired public FilterService(RemoteServicesProperties remoteServicesProperties, RestTemplate restTemplate) { this.baseUri = remoteServicesProperties.getServiceUri("filter-server"); @@ -64,8 +64,7 @@ public String evaluateFilter(UUID networkUuid, String variantId, String filter) if (variantId != null && !variantId.isBlank()) { uriComponentsBuilder.queryParam("variantId", variantId); } - var uriComponent = uriComponentsBuilder - .build(); + var uriComponent = uriComponentsBuilder.build(); var headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -83,6 +82,28 @@ public String evaluateFilter(UUID networkUuid, String variantId, String filter) } } + public List evaluateGlobalFilter(@NonNull final UUID networkUuid, @NonNull final String variantId, + @NonNull final List equipmentTypes, @NonNull final GlobalFilter filter) { + final UriComponents uriComponent = UriComponentsBuilder.fromHttpUrl(getBaseUri()) + .pathSegment(FILTER_API_VERSION, "global-filter", "evaluate") + .queryParam("networkUuid", networkUuid) + .queryParam("variantId", variantId) + .queryParam("equipmentTypes", equipmentTypes) + .build(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + try { + return restTemplate.exchange(uriComponent.toUri(), HttpMethod.POST, new HttpEntity<>(filter, headers), new ParameterizedTypeReference>() { }) + .getBody(); + } catch (final HttpStatusCodeException ex) { + if (HttpStatus.NOT_FOUND.equals(ex.getStatusCode())) { + throw new StudyException(NETWORK_NOT_FOUND); + } else { + throw handleHttpError(ex, EVALUATE_FILTER_FAILED); + } + } + } + public String exportFilter(UUID networkUuid, UUID filterUuid) { Objects.requireNonNull(networkUuid); Objects.requireNonNull(filterUuid); diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index c5b89334cf..219cdd0fbd 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -15,6 +15,8 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.NonNull; import org.apache.commons.collections4.CollectionUtils; +import org.gridsuite.filter.globalfilter.GlobalFilter; +import org.gridsuite.filter.utils.EquipmentType; import org.gridsuite.study.server.StudyConstants; import org.gridsuite.study.server.StudyException; import org.gridsuite.study.server.dto.*; @@ -307,6 +309,14 @@ public BasicStudyInfos createStudy(UUID caseUuid, String userId, UUID studyUuid, return basicStudyInfos; } + @Transactional(readOnly = true) + public void assertIsRootNetworkAndNodeInStudy(@NonNull final UUID studyUuid, @NonNull final UUID rootNetworkId, @NonNull final UUID nodeUuid) { + this.rootNetworkService.assertIsRootNetworkInStudy(studyUuid, rootNetworkId); + if (!studyUuid.equals(this.networkModificationTreeService.getStudyUuidForNodeId(nodeUuid))) { + throw new StudyException(NODE_NOT_FOUND); + } + } + @Transactional public void deleteRootNetworks(UUID studyUuid, List rootNetworksUuids) { assertIsStudyExist(studyUuid); @@ -3364,6 +3374,17 @@ public String evaluateFilter(UUID nodeUuid, UUID rootNetworkUuid, boolean inUpst return filterService.evaluateFilter(rootNetworkService.getNetworkUuid(rootNetworkUuid), networkModificationTreeService.getVariantId(nodeUuidToSearchIn, rootNetworkUuid), filter); } + @Transactional(readOnly = true) + public List evaluateGlobalFilter(@NonNull final UUID nodeUuid, @NonNull final UUID rootNetworkUuid, + @NonNull final List equipmentTypes, @NonNull final GlobalFilter filter) { + return filterService.evaluateGlobalFilter( + rootNetworkService.getNetworkUuid(rootNetworkUuid), + networkModificationTreeService.getVariantId(getNodeUuidToSearchIn(nodeUuid, rootNetworkUuid, true), rootNetworkUuid), + equipmentTypes, + filter + ); + } + @Transactional(readOnly = true) public String exportFilter(UUID rootNetworkUuid, UUID filterUuid) { return filterService.exportFilter(rootNetworkService.getNetworkUuid(rootNetworkUuid), filterUuid); From 23ee239e64a15f09686987f936588cceb6c3966e Mon Sep 17 00:00:00 2001 From: Tristan Chuine Date: Thu, 2 Oct 2025 09:59:45 +0200 Subject: [PATCH 2/9] checkstyle --- .../java/org/gridsuite/study/server/service/FilterService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/gridsuite/study/server/service/FilterService.java b/src/main/java/org/gridsuite/study/server/service/FilterService.java index 47422e09fe..3e60a12153 100644 --- a/src/main/java/org/gridsuite/study/server/service/FilterService.java +++ b/src/main/java/org/gridsuite/study/server/service/FilterService.java @@ -15,7 +15,6 @@ import org.gridsuite.study.server.StudyException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.core.ResolvableType; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpStatusCodeException; From 6a04ef636628c4a3b91e4e37455092645f7d30b1 Mon Sep 17 00:00:00 2001 From: Tristan <135599584+Tristan-WorkGH@users.noreply.github.com> Date: Thu, 2 Oct 2025 10:21:54 +0200 Subject: [PATCH 3/9] fix url --- .../org/gridsuite/study/server/controller/StudyController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index 28d4b90302..b2eccecf6e 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -2347,7 +2347,7 @@ public ResponseEntity evaluateFilter( return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(studyService.evaluateFilter(nodeUuid, rootNetworkUuid, inUpstreamBuiltParentNode, filter)); } - @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/global-filter/evaluate", + @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/global-filter", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Evaluate a filter to get matched elements") @ApiResponse(responseCode = "200", description = "The list of matched elements") From fc26a292db3f1780130c137556643a7a746bf08e Mon Sep 17 00:00:00 2001 From: Tristan <135599584+Tristan-WorkGH@users.noreply.github.com> Date: Thu, 2 Oct 2025 10:27:35 +0200 Subject: [PATCH 4/9] fix of fix --- .../org/gridsuite/study/server/controller/StudyController.java | 2 +- .../java/org/gridsuite/study/server/service/FilterService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index b2eccecf6e..28d4b90302 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -2347,7 +2347,7 @@ public ResponseEntity evaluateFilter( return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(studyService.evaluateFilter(nodeUuid, rootNetworkUuid, inUpstreamBuiltParentNode, filter)); } - @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/global-filter", + @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/global-filter/evaluate", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Evaluate a filter to get matched elements") @ApiResponse(responseCode = "200", description = "The list of matched elements") diff --git a/src/main/java/org/gridsuite/study/server/service/FilterService.java b/src/main/java/org/gridsuite/study/server/service/FilterService.java index 3e60a12153..7cc4dec806 100644 --- a/src/main/java/org/gridsuite/study/server/service/FilterService.java +++ b/src/main/java/org/gridsuite/study/server/service/FilterService.java @@ -84,7 +84,7 @@ public String evaluateFilter(UUID networkUuid, String variantId, String filter) public List evaluateGlobalFilter(@NonNull final UUID networkUuid, @NonNull final String variantId, @NonNull final List equipmentTypes, @NonNull final GlobalFilter filter) { final UriComponents uriComponent = UriComponentsBuilder.fromHttpUrl(getBaseUri()) - .pathSegment(FILTER_API_VERSION, "global-filter", "evaluate") + .pathSegment(FILTER_API_VERSION, "global-filter") .queryParam("networkUuid", networkUuid) .queryParam("variantId", variantId) .queryParam("equipmentTypes", equipmentTypes) From 957191be9bdbf3b3c072b07152ed43ee593a3ae7 Mon Sep 17 00:00:00 2001 From: Franck LECUYER Date: Thu, 9 Oct 2025 14:08:09 +0200 Subject: [PATCH 5/9] Add missing unit test for coverage Signed-off-by: Franck LECUYER --- .../study/server/StudyConstants.java | 1 + .../server/controller/StudyController.java | 2 +- .../study/server/FilterServiceTest.java | 33 +++++++++++++++++++ .../study/server/utils/WireMockUtils.java | 17 ++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/study/server/StudyConstants.java b/src/main/java/org/gridsuite/study/server/StudyConstants.java index 82046a6397..983c242584 100644 --- a/src/main/java/org/gridsuite/study/server/StudyConstants.java +++ b/src/main/java/org/gridsuite/study/server/StudyConstants.java @@ -46,6 +46,7 @@ private StudyConstants() { public static final String QUERY_PARAM_VARIANT_ID = "variantId"; public static final String QUERY_PARAM_NETWORK_UUID = "networkUuid"; public static final String QUERY_PARAM_EQUIPMENT_TYPE = "equipmentType"; + public static final String QUERY_PARAM_EQUIPMENT_TYPES = "equipmentTypes"; public static final String QUERY_PARAM_ELEMENT_TYPE = "elementType"; public static final String QUERY_PARAM_SIDE = "side"; public static final String QUERY_PARAM_NOMINAL_VOLTAGES = "nominalVoltages"; diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index a33691e7ae..50cb1f36a7 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -2257,7 +2257,7 @@ public ResponseEntity evaluateFilter( @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/global-filter/evaluate", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Evaluate a filter to get matched elements") + @Operation(summary = "Evaluate a global filter to get matched elements") @ApiResponse(responseCode = "200", description = "The list of matched elements") public ResponseEntity> evaluateGlobalFilter( @Parameter(description = "Study uuid") @PathVariable("studyUuid") UUID studyUuid, diff --git a/src/test/java/org/gridsuite/study/server/FilterServiceTest.java b/src/test/java/org/gridsuite/study/server/FilterServiceTest.java index 2d26c7c78f..623f59f747 100644 --- a/src/test/java/org/gridsuite/study/server/FilterServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/FilterServiceTest.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.tomakehurst.wiremock.WireMockServer; import com.powsybl.commons.exceptions.UncheckedInterruptedException; +import org.gridsuite.filter.utils.EquipmentType; import org.gridsuite.study.server.networkmodificationtree.dto.RootNode; import org.gridsuite.study.server.repository.StudyEntity; import org.gridsuite.study.server.repository.StudyRepository; @@ -169,6 +170,38 @@ void testEvaluateFilter() throws Exception { wireMockUtils.verifyFilterEvaluate(stubUuid, NETWORK_UUID_STRING); } + @Test + void testEvaluateGlobalFilter() throws Exception { + StudyEntity studyEntity = insertDummyStudy(UUID.fromString(NETWORK_UUID_STRING), CASE_UUID); + UUID studyNameUserIdUuid = studyEntity.getId(); + UUID firstRootNetworkUuid = studyTestUtils.getOneRootNetworkUuid(studyNameUserIdUuid); + UUID rootNodeUuid = getRootNode(studyNameUserIdUuid).getId(); + + // whatever string is allowed but given here a json string for more expressive + final String sendBody = """ + { + "nominalV" : ["380", "225"], + "countryCode": ["FR", "BE"], + "genericFilter": ["c6c15d08-81e9-47a1-9cdb-7be22f017ad5"], + "substationProperty": {} + } + """; + + String responseBody = "[\"GEN\"]"; + + UUID stubUuid = wireMockUtils.stubGlobalFilterEvaluate(NETWORK_UUID_STRING, List.of(EquipmentType.GENERATOR), responseBody); + + MvcResult mvcResult = mockMvc.perform(post("/v1/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/global-filter/evaluate?equipmentTypes=GENERATOR", + studyNameUserIdUuid, firstRootNetworkUuid, rootNodeUuid) + .content(sendBody).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + String resultAsString = mvcResult.getResponse().getContentAsString(); + assertEquals(responseBody, resultAsString); + + wireMockUtils.verifyGlobalFilterEvaluate(stubUuid, NETWORK_UUID_STRING, List.of(EquipmentType.GENERATOR)); + } + @Test void testEvaluateFilterNotFoundError() throws Exception { UUID stubUuid = wireMockUtils.stubFilterEvaluateNotFoundError(NETWORK_UUID_STRING); diff --git a/src/test/java/org/gridsuite/study/server/utils/WireMockUtils.java b/src/test/java/org/gridsuite/study/server/utils/WireMockUtils.java index d259e10c5a..f3ac6cc9a0 100644 --- a/src/test/java/org/gridsuite/study/server/utils/WireMockUtils.java +++ b/src/test/java/org/gridsuite/study/server/utils/WireMockUtils.java @@ -15,6 +15,7 @@ import com.github.tomakehurst.wiremock.matching.StringValuePattern; import com.github.tomakehurst.wiremock.stubbing.ServeEvent; import com.powsybl.iidm.network.TwoSides; +import org.gridsuite.filter.utils.EquipmentType; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -524,6 +525,15 @@ public UUID stubFilterEvaluate(String networkUuid, String responseBody) { ).getId(); } + public UUID stubGlobalFilterEvaluate(String networkUuid, List equipmentTypes, String responseBody) { + return wireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/v1/global-filter")) + .withQueryParam(NETWORK_UUID, WireMock.equalTo(networkUuid)) + .withQueryParam(QUERY_PARAM_VARIANT_ID, WireMock.equalTo("")) + .withQueryParam(QUERY_PARAM_EQUIPMENT_TYPES, WireMock.equalTo(String.join(",", equipmentTypes.stream().map(EquipmentType::name).toList()))) + .willReturn(WireMock.ok().withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).withBody(responseBody)) + ).getId(); + } + public UUID stubFilterEvaluateNotFoundError(String networkUuid) { return wireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo("/v1/filters/evaluate")) .withQueryParam(NETWORK_UUID, WireMock.equalTo(networkUuid)) @@ -543,6 +553,13 @@ public void verifyFilterEvaluate(UUID stubUuid, String networkUuid) { Map.of(NETWORK_UUID, WireMock.equalTo(networkUuid))); } + public void verifyGlobalFilterEvaluate(UUID stubUuid, String networkUuid, List equipmentTypes) { + verifyPostRequest(stubUuid, "/v1/global-filter", + Map.of(NETWORK_UUID, WireMock.equalTo(networkUuid), + QUERY_PARAM_VARIANT_ID, WireMock.equalTo(""), + QUERY_PARAM_EQUIPMENT_TYPES, WireMock.equalTo(String.join(",", equipmentTypes.stream().map(EquipmentType::name).toList())))); + } + public UUID stubFilterExport(String networkUuid, String filterUuid, String responseBody) { return wireMock.stubFor(WireMock.get(WireMock.urlPathEqualTo("/v1/filters/" + filterUuid + "/export")) .withQueryParam(NETWORK_UUID, WireMock.equalTo(networkUuid)) From 81dda71fdc920df508ed18976e391271381a3d31 Mon Sep 17 00:00:00 2001 From: David BRAQUART Date: Mon, 13 Oct 2025 16:34:34 +0200 Subject: [PATCH 6/9] rev: use constants Signed-off-by: David BRAQUART --- .../study/server/service/FilterService.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/service/FilterService.java b/src/main/java/org/gridsuite/study/server/service/FilterService.java index 7cc4dec806..9d5d4f8532 100644 --- a/src/main/java/org/gridsuite/study/server/service/FilterService.java +++ b/src/main/java/org/gridsuite/study/server/service/FilterService.java @@ -28,6 +28,10 @@ import static org.gridsuite.study.server.StudyConstants.DELIMITER; import static org.gridsuite.study.server.StudyConstants.FILTER_API_VERSION; +import static org.gridsuite.study.server.StudyConstants.IDS; +import static org.gridsuite.study.server.StudyConstants.NETWORK_UUID; +import static org.gridsuite.study.server.StudyConstants.QUERY_PARAM_EQUIPMENT_TYPES; +import static org.gridsuite.study.server.StudyConstants.QUERY_PARAM_VARIANT_ID; import static org.gridsuite.study.server.StudyException.Type.EVALUATE_FILTER_FAILED; import static org.gridsuite.study.server.StudyException.Type.NETWORK_NOT_FOUND; import static org.gridsuite.study.server.utils.StudyUtils.handleHttpError; @@ -59,9 +63,9 @@ public String evaluateFilter(UUID networkUuid, String variantId, String filter) String endPointUrl = getBaseUri() + DELIMITER + FILTER_API_VERSION + FILTER_END_POINT_EVALUATE; UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(endPointUrl); - uriComponentsBuilder.queryParam("networkUuid", networkUuid); + uriComponentsBuilder.queryParam(NETWORK_UUID, networkUuid); if (variantId != null && !variantId.isBlank()) { - uriComponentsBuilder.queryParam("variantId", variantId); + uriComponentsBuilder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); } var uriComponent = uriComponentsBuilder.build(); @@ -85,9 +89,9 @@ public List evaluateGlobalFilter(@NonNull final UUID networkUuid, @NonNu @NonNull final List equipmentTypes, @NonNull final GlobalFilter filter) { final UriComponents uriComponent = UriComponentsBuilder.fromHttpUrl(getBaseUri()) .pathSegment(FILTER_API_VERSION, "global-filter") - .queryParam("networkUuid", networkUuid) - .queryParam("variantId", variantId) - .queryParam("equipmentTypes", equipmentTypes) + .queryParam(NETWORK_UUID, networkUuid) + .queryParam(QUERY_PARAM_VARIANT_ID, variantId) + .queryParam(QUERY_PARAM_EQUIPMENT_TYPES, equipmentTypes) .build(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -109,7 +113,7 @@ public String exportFilter(UUID networkUuid, UUID filterUuid) { String endPointUrl = getBaseUri() + DELIMITER + FILTER_API_VERSION + FILTER_END_POINT_EXPORT; UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(endPointUrl); - uriComponentsBuilder.queryParam("networkUuid", networkUuid); + uriComponentsBuilder.queryParam(NETWORK_UUID, networkUuid); var uriComponent = uriComponentsBuilder.buildAndExpand(filterUuid); return restTemplate.getForObject(uriComponent.toUriString(), String.class); @@ -121,11 +125,11 @@ public String exportFilters(UUID networkUuid, List filtersUuid, String var String endPointUrl = getBaseUri() + DELIMITER + FILTER_API_VERSION + FILTERS_END_POINT_EXPORT; UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(endPointUrl); - uriComponentsBuilder.queryParam("networkUuid", networkUuid); + uriComponentsBuilder.queryParam(NETWORK_UUID, networkUuid); if (variantId != null && !variantId.isBlank()) { - uriComponentsBuilder.queryParam("variantId", variantId); + uriComponentsBuilder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); } - uriComponentsBuilder.queryParam("ids", filtersUuid); + uriComponentsBuilder.queryParam(IDS, filtersUuid); var uriComponent = uriComponentsBuilder.buildAndExpand(); return restTemplate.getForObject(uriComponent.toUriString(), String.class); @@ -137,8 +141,8 @@ public String evaluateFilters(UUID networkUuid, List filtersUuid) { String endPointUrl = getBaseUri() + DELIMITER + FILTER_API_VERSION + FILTER_END_POINT_EVALUATE_IDS; UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(endPointUrl); - uriComponentsBuilder.queryParam("networkUuid", networkUuid); - uriComponentsBuilder.queryParam("ids", filtersUuid); + uriComponentsBuilder.queryParam(NETWORK_UUID, networkUuid); + uriComponentsBuilder.queryParam(IDS, filtersUuid); var uriComponent = uriComponentsBuilder.buildAndExpand(); return restTemplate.getForObject(uriComponent.toUriString(), String.class); From ef13affb0995f33795a0a05aff56c542d043941d Mon Sep 17 00:00:00 2001 From: Franck LECUYER Date: Tue, 21 Oct 2025 13:14:35 +0200 Subject: [PATCH 7/9] Upgrade filter version to 1.12.0 Signed-off-by: Franck LECUYER --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 70f5f91fe1..0e2a545105 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,7 @@ 43.0.0 + 1.12.0 org.gridsuite.study.server 5.0.0-alpha.14 1.0.5 @@ -147,7 +148,7 @@ org.gridsuite gridsuite-filter - 1.10.0-SNAPSHOT + ${gridsuite-filter.version} io.projectreactor From a7c652c1ff51d00042e7b2dd9bf10664b621be2c Mon Sep 17 00:00:00 2001 From: Franck LECUYER Date: Tue, 21 Oct 2025 13:40:30 +0200 Subject: [PATCH 8/9] Improve test in code Signed-off-by: Franck LECUYER --- .../org/gridsuite/study/server/service/FilterService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/service/FilterService.java b/src/main/java/org/gridsuite/study/server/service/FilterService.java index fab0a1b59c..bb35a77d31 100644 --- a/src/main/java/org/gridsuite/study/server/service/FilterService.java +++ b/src/main/java/org/gridsuite/study/server/service/FilterService.java @@ -9,6 +9,7 @@ import lombok.Getter; import lombok.NonNull; +import org.apache.commons.lang3.StringUtils; import org.gridsuite.filter.globalfilter.GlobalFilter; import org.gridsuite.filter.utils.EquipmentType; import org.gridsuite.study.server.RemoteServicesProperties; @@ -64,7 +65,7 @@ public String evaluateFilter(UUID networkUuid, String variantId, String filter) UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(endPointUrl); uriComponentsBuilder.queryParam(NETWORK_UUID, networkUuid); - if (variantId != null && !variantId.isBlank()) { + if (!StringUtils.isBlank(variantId)) { uriComponentsBuilder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); } var uriComponent = uriComponentsBuilder.build(); @@ -126,7 +127,7 @@ public String exportFilters(UUID networkUuid, List filtersUuid, String var UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(endPointUrl); uriComponentsBuilder.queryParam(NETWORK_UUID, networkUuid); - if (variantId != null && !variantId.isBlank()) { + if (!StringUtils.isBlank(variantId)) { uriComponentsBuilder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); } uriComponentsBuilder.queryParam(IDS, filtersUuid); From 1782f423720b1d67eb78a3d6cbb6165b2c30d758 Mon Sep 17 00:00:00 2001 From: Franck LECUYER Date: Tue, 21 Oct 2025 14:27:33 +0200 Subject: [PATCH 9/9] Improve coverage Signed-off-by: Franck LECUYER --- .../study/server/FilterServiceTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/test/java/org/gridsuite/study/server/FilterServiceTest.java b/src/test/java/org/gridsuite/study/server/FilterServiceTest.java index 212c7d7e47..3b95d56885 100644 --- a/src/test/java/org/gridsuite/study/server/FilterServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/FilterServiceTest.java @@ -11,6 +11,8 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.powsybl.commons.exceptions.UncheckedInterruptedException; import org.gridsuite.filter.utils.EquipmentType; +import org.gridsuite.study.server.networkmodificationtree.dto.InsertMode; +import org.gridsuite.study.server.networkmodificationtree.dto.NetworkModificationNode; import org.gridsuite.study.server.networkmodificationtree.dto.RootNode; import org.gridsuite.study.server.repository.StudyEntity; import org.gridsuite.study.server.repository.StudyRepository; @@ -39,6 +41,7 @@ import java.util.stream.Collectors; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.gridsuite.study.server.utils.TestUtils.createModificationNodeInfo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -59,6 +62,7 @@ class FilterServiceTest { private static final String FILTER_UUID_STRING = "c6c15d08-81e9-47a1-9cdb-7be22f017ad5"; private static final List FILTERS_UUID_STRING = List.of("fc3aa057-5fa4-4173-b1a8-16028f5eefd1", "f8773f32-f77c-4126-8c6f-a4af8bf6f788"); private static final UUID CASE_UUID = UUID.fromString(CASE_UUID_STRING); + private static final String NODE_1_NAME = "node1"; @Autowired private MockMvc mockMvc; @@ -127,6 +131,7 @@ void testEvaluateFilter() throws Exception { UUID studyNameUserIdUuid = studyEntity.getId(); UUID firstRootNetworkUuid = studyTestUtils.getOneRootNetworkUuid(studyNameUserIdUuid); UUID rootNodeUuid = getRootNode(studyNameUserIdUuid).getId(); + NetworkModificationNode firstNode = networkModificationTreeService.createNode(studyEntity, rootNodeUuid, createModificationNodeInfo(NODE_1_NAME), InsertMode.AFTER, null); // whatever string is allowed but given here a json string for more expressive final String sendBody = """ @@ -166,6 +171,17 @@ void testEvaluateFilter() throws Exception { assertEquals(responseBody, resultAsString); wireMockUtils.verifyFilterEvaluate(stubUuid, NETWORK_UUID_STRING); + + // evaluate on first node + mvcResult = mockMvc.perform(post("/v1/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/filters/evaluate", + studyNameUserIdUuid, firstRootNetworkUuid, firstNode.getId()) + .content(sendBody).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + resultAsString = mvcResult.getResponse().getContentAsString(); + assertEquals(responseBody, resultAsString); + + wireMockUtils.verifyFilterEvaluate(stubUuid, NETWORK_UUID_STRING); } @Test @@ -363,6 +379,8 @@ void testExportFilters() throws Exception { UUID firstRootNetworkUuid = studyTestUtils.getOneRootNetworkUuid(studyEntity.getId()); UUID studyUuid = studyEntity.getId(); UUID rootNodeUuid = getRootNode(studyUuid).getId(); + NetworkModificationNode firstNode = networkModificationTreeService.createNode(studyEntity, rootNodeUuid, createModificationNodeInfo(NODE_1_NAME), InsertMode.AFTER, null); + String responseBody = """ [ { @@ -404,5 +422,15 @@ void testExportFilters() throws Exception { assertEquals(responseBody, resultAsString); wireMockUtils.verifyFiltersExport(stubUuid, FILTERS_UUID_STRING, NETWORK_UUID_STRING); + + // export on first node + mvcResult = mockMvc.perform(get("/v1/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/filters/elements?filtersUuid=" + FILTERS_UUID_STRING.stream().collect(Collectors.joining(",")), + studyUuid, firstRootNetworkUuid, firstNode.getId())) + .andExpect(status().isOk()) + .andReturn(); + resultAsString = mvcResult.getResponse().getContentAsString(); + assertEquals(responseBody, resultAsString); + + wireMockUtils.verifyFiltersExport(stubUuid, FILTERS_UUID_STRING, NETWORK_UUID_STRING); } }