From 3da711f330f45b1c9fa15cb3e466432c88af4d54 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Thu, 5 Feb 2026 10:04:45 +0100 Subject: [PATCH 01/11] draft version --- .../server/SecurityAnalysisController.java | 8 ++--- .../server/dto/ContingencyListsDTO.java | 36 +++++++++++++++++++ .../server/dto/RunContextParametersInfos.java | 3 -- .../dto/SecurityAnalysisParametersDTO.java | 2 ++ .../dto/SecurityAnalysisParametersValues.java | 2 ++ .../server/entities/ContingencyEntity.java | 1 + .../entities/ContingencyListsEmbeddable.java | 34 ++++++++++++++++++ .../SecurityAnalysisParametersEntity.java | 18 ++++++++++ .../server/service/ActionsService.java | 2 +- .../SecurityAnalysisParametersService.java | 12 +++++-- .../SecurityAnalysisResultContext.java | 18 ---------- .../service/SecurityAnalysisRunContext.java | 8 ++--- .../SecurityAnalysisWorkerService.java | 7 ++-- .../server/SecurityAnalysisProviderMock.java | 9 ++--- .../server/service/ActionsServiceTest.java | 6 ++-- 15 files changed, 121 insertions(+), 45 deletions(-) create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyListsEmbeddable.java diff --git a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java index 4184e694..7b415500 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java @@ -67,7 +67,6 @@ public SecurityAnalysisController(SecurityAnalysisService securityAnalysisServic schema = @Schema(implementation = SecurityAnalysisResult.class))})}) public ResponseEntity run(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid, @Parameter(description = "Variant Id") @RequestParam(name = "variantId", required = false) String variantId, - @Parameter(description = "Contingency list name") @RequestParam(name = "contingencyListName", required = false) List contigencyListNames, @Parameter(description = "Provider") @RequestParam(name = "provider", required = false) String provider, @Parameter(description = "reportUuid") @RequestParam(name = "reportUuid", required = false) UUID reportUuid, @Parameter(description = "reporterId") @RequestParam(name = "reporterId", required = false) String reporterId, @@ -79,14 +78,14 @@ public ResponseEntity run(@Parameter(description = "Netw securityAnalysisParametersService.createRunContext( networkUuid, variantId, - new RunContextParametersInfos(contigencyListNames, parametersUuid, loadFlowParametersUuid), + new RunContextParametersInfos(parametersUuid, loadFlowParametersUuid), null, new ReportInfos(reportUuid, reporterId, reportType), userId)); return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result); } - @PostMapping(value = "/networks/{networkUuid}/run-and-save", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + @PostMapping(value = "/networks/{networkUuid}/run-and-save", produces = APPLICATION_JSON_VALUE) @Operation(summary = "Run a security analysis on a network and save results in the database") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis has been performed and results have been saved to database", @@ -94,7 +93,6 @@ public ResponseEntity run(@Parameter(description = "Netw schema = @Schema(implementation = SecurityAnalysisResult.class))})}) public ResponseEntity runAndSave(@Parameter(description = "Network UUID") @PathVariable("networkUuid") UUID networkUuid, @Parameter(description = "Variant Id") @RequestParam(name = "variantId", required = false) String variantId, - @Parameter(description = "Contingency list name") @RequestParam(name = "contingencyListName", required = false) List contigencyListNames, @Parameter(description = "Result receiver") @RequestParam(name = "receiver", required = false) String receiver, @Parameter(description = "reportUuid") @RequestParam(name = "reportUuid", required = false) UUID reportUuid, @Parameter(description = "reporterId") @RequestParam(name = "reporterId", required = false) String reporterId, @@ -106,7 +104,7 @@ public ResponseEntity runAndSave(@Parameter(description = "Network UUID") securityAnalysisParametersService.createRunContext( networkUuid, variantId, - new RunContextParametersInfos(contigencyListNames, parametersUuid, loadFlowParametersUuid), + new RunContextParametersInfos(parametersUuid, loadFlowParametersUuid), receiver, new ReportInfos(reportUuid, reporterId, reportType), userId diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java new file mode 100644 index 00000000..0321e6a2 --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server.dto; + +import lombok.*; +import org.gridsuite.securityanalysis.server.entities.ContingencyListsEmbeddable; + +import java.util.UUID; + +/** + * @author Caroline Jeandat {@literal } + */ +@Data +@Builder +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class ContingencyListsDTO { + private UUID id; + private String name; + private boolean activated; + + public ContingencyListsDTO(ContingencyListsEmbeddable contingencyListsEmbeddable) { + this.id = contingencyListsEmbeddable.getId(); + this.name = contingencyListsEmbeddable.getName(); + this.activated = contingencyListsEmbeddable.isActivated(); + } + + public ContingencyListsEmbeddable toEmbeddable() { + return new ContingencyListsEmbeddable(this); + } +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/RunContextParametersInfos.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/RunContextParametersInfos.java index 75c70925..5061ac6b 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/RunContextParametersInfos.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/RunContextParametersInfos.java @@ -10,7 +10,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; -import java.util.List; import java.util.UUID; /** @@ -20,8 +19,6 @@ @Getter @Schema(description = "to help create a securityAnalysisRunContext") public class RunContextParametersInfos { - private List contingencyListNames; - private UUID securityAnalysisParametersUuid; private UUID loadFlowParametersUuid; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java index 1e864d7d..ff68e8cd 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java @@ -10,9 +10,11 @@ import lombok.Builder; import java.util.List; +import java.util.UUID; @Builder public record SecurityAnalysisParametersDTO( SecurityAnalysisParameters securityAnalysisParameters, + List contingencyListsUuids, List> limitReductions ) { } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java index 99c2892b..07522b71 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java @@ -36,6 +36,8 @@ public class SecurityAnalysisParametersValues { private double flowProportionalThreshold; + private List contingencyLists; + private List limitReductions; public SecurityAnalysisParametersEntity toEntity() { diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyEntity.java index 2c8f5656..d9bddad7 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyEntity.java @@ -43,6 +43,7 @@ public ContingencyEntity(String contingencyId, String status, List} + */ +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Embeddable +public class ContingencyListsEmbeddable { + private UUID id; + private String name; + private boolean activated; + + public ContingencyListsEmbeddable(ContingencyListsDTO contingencyListsDTO) { + this.id = contingencyListsDTO.getId(); + this.name = contingencyListsDTO.getName(); + this.activated = contingencyListsDTO.isActivated(); + } +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java index 13aed58d..eb8b76a0 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java @@ -55,11 +55,28 @@ public SecurityAnalysisParametersEntity(SecurityAnalysisParametersValues securit @Column(name = "flowProportionalThreshold") private double flowProportionalThreshold; + @ElementCollection + @CollectionTable( + name = "contingency_lists", + joinColumns = @JoinColumn(name = "security_analysis_parameters_id") + ) + private List contingencyLists; + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "security_analysis_parameters_id", foreignKey = @ForeignKey(name = "securityAnalysisParametersEntity_limitReductions_fk")) @OrderColumn(name = "index") private List limitReductions; + public List getActivatedContingencyListUuids() { + if (contingencyLists == null) { + return List.of(); + } + return this.contingencyLists.stream() + .filter(ContingencyListsEmbeddable::isActivated) + .map(ContingencyListsEmbeddable::getId) + .toList(); + } + public List> toLimitReductionsValues() { return this.limitReductions.stream().map(LimitReductionEntity::getReductions).map(ArrayList::new).collect(Collectors.toList()); } @@ -75,6 +92,7 @@ private void assignAttributes(SecurityAnalysisParametersValues securityAnalysisP this.highVoltageProportionalThreshold = securityAnalysisParametersValues.getHighVoltageProportionalThreshold(); this.lowVoltageAbsoluteThreshold = securityAnalysisParametersValues.getLowVoltageAbsoluteThreshold(); this.lowVoltageProportionalThreshold = securityAnalysisParametersValues.getLowVoltageProportionalThreshold(); + this.contingencyLists = securityAnalysisParametersValues.getContingencyLists().stream().map(ContingencyListsEmbeddable::new).toList(); assignLimitReductions(securityAnalysisParametersValues.getLimitReductionsValues()); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java index 4e2a8a64..8e686f39 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/ActionsService.java @@ -45,7 +45,7 @@ public ActionsService( this.restTemplate = restTemplate; } - public List getContingencyList(List ids, UUID networkUuid, String variantId) { + public List getContingencyList(List ids, UUID networkUuid, String variantId) { Objects.requireNonNull(ids); Objects.requireNonNull(networkUuid); if (ids.isEmpty()) { diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java index d2f16aef..e4811486 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java @@ -41,6 +41,7 @@ public class SecurityAnalysisParametersService { private static final double DEFAULT_HIGH_VOLTAGE_PROPORTIONAL_THRESHOLD = 0.01; // meaning 1.0 % private static final double DEFAULT_LOW_VOLTAGE_ABSOLUTE_THRESHOLD = 1.0; // 1.0 kV private static final double DEFAULT_HIGH_VOLTAGE_ABSOLUTE_THRESHOLD = 1.0; // 1.0 kV + private static final List DEFAULT_CONTINGENCY_LISTS = new ArrayList<>(); public SecurityAnalysisParametersService(@NonNull SecurityAnalysisParametersRepository securityAnalysisParametersRepository, @NonNull LoadFlowService loadFlowService, @Value("${security-analysis.default-provider}") String defaultProvider, @NonNull LimitReductionService limitReductionService) { @@ -69,7 +70,6 @@ public SecurityAnalysisRunContext createRunContext(UUID networkUuid, String vari return new SecurityAnalysisRunContext( networkUuid, variantId, - runContextParametersInfos.getContingencyListNames(), receiver, providerToUse, parameters, @@ -81,18 +81,24 @@ public SecurityAnalysisRunContext createRunContext(UUID networkUuid, String vari public SecurityAnalysisParametersDTO toSecurityAnalysisParameters(SecurityAnalysisParametersEntity entity) { SecurityAnalysisParameters securityAnalysisParameters = SecurityAnalysisParameters.load(); List> limitReductions = new ArrayList<>(); + List activatedContingencyListUuids = new ArrayList<>(); if (entity == null) { // the default values are overloaded securityAnalysisParameters.setIncreasedViolationsParameters(getIncreasedViolationsParameters(DEFAULT_FLOW_PROPORTIONAL_THRESHOLD, DEFAULT_LOW_VOLTAGE_PROPORTIONAL_THRESHOLD, DEFAULT_LOW_VOLTAGE_ABSOLUTE_THRESHOLD, DEFAULT_HIGH_VOLTAGE_PROPORTIONAL_THRESHOLD, DEFAULT_HIGH_VOLTAGE_ABSOLUTE_THRESHOLD)); } else { securityAnalysisParameters.setIncreasedViolationsParameters(getIncreasedViolationsParameters(entity.getFlowProportionalThreshold(), entity.getLowVoltageProportionalThreshold(), entity.getLowVoltageAbsoluteThreshold(), entity.getHighVoltageProportionalThreshold(), entity.getHighVoltageAbsoluteThreshold())); limitReductions = entity.toLimitReductionsValues(); + activatedContingencyListUuids = entity.getActivatedContingencyListUuids(); } if (limitReductions.isEmpty()) { limitReductions = limitReductionService.getDefaultValues(); } - return SecurityAnalysisParametersDTO.builder().securityAnalysisParameters(securityAnalysisParameters).limitReductions(limitReductions).build(); + return SecurityAnalysisParametersDTO.builder() + .securityAnalysisParameters(securityAnalysisParameters) + .contingencyListsUuids(activatedContingencyListUuids) + .limitReductions(limitReductions) + .build(); } public SecurityAnalysisParametersValues toSecurityAnalysisParametersValues(SecurityAnalysisParametersEntity entity) { @@ -103,6 +109,7 @@ public SecurityAnalysisParametersValues toSecurityAnalysisParametersValues(Secur .highVoltageProportionalThreshold(entity.getHighVoltageProportionalThreshold()) .lowVoltageAbsoluteThreshold(entity.getLowVoltageAbsoluteThreshold()) .lowVoltageProportionalThreshold(entity.getLowVoltageProportionalThreshold()) + .contingencyLists(entity.getContingencyLists().stream().map(ContingencyListsDTO::new).toList()) .limitReductions(getLimitReductionsForProvider(entity).orElse(null)) .build(); } @@ -134,6 +141,7 @@ public SecurityAnalysisParametersValues getDefaultSecurityAnalysisParametersValu .highVoltageAbsoluteThreshold(DEFAULT_HIGH_VOLTAGE_ABSOLUTE_THRESHOLD) .highVoltageProportionalThreshold(DEFAULT_HIGH_VOLTAGE_PROPORTIONAL_THRESHOLD) .flowProportionalThreshold(DEFAULT_FLOW_PROPORTIONAL_THRESHOLD) + .contingencyLists(DEFAULT_CONTINGENCY_LISTS) .limitReductions(limitReductionService.createDefaultLimitReductions()) .build(); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultContext.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultContext.java index 8843b37f..a7cc2289 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultContext.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultContext.java @@ -24,27 +24,16 @@ * @author Geoffroy Jamgotchian */ public class SecurityAnalysisResultContext extends AbstractResultContext { - public static final String CONTINGENCY_LIST_NAMES_HEADER = "contingencyListNames"; - public SecurityAnalysisResultContext(UUID resultUuid, SecurityAnalysisRunContext runContext) { super(resultUuid, runContext); } - private static List getHeaderList(MessageHeaders headers, String name) { - String header = (String) headers.get(name); - if (header == null || header.isEmpty()) { - return Collections.emptyList(); - } - return Arrays.asList(header.split(",")); - } - public static SecurityAnalysisResultContext fromMessage(Message message, ObjectMapper objectMapper) { Objects.requireNonNull(message); MessageHeaders headers = message.getHeaders(); UUID resultUuid = UUID.fromString(getNonNullHeader(headers, HEADER_RESULT_UUID)); UUID networkUuid = UUID.fromString(getNonNullHeader(headers, NETWORK_UUID_HEADER)); String variantId = (String) headers.get(VARIANT_ID_HEADER); - List contingencyListNames = getHeaderList(headers, CONTINGENCY_LIST_NAMES_HEADER); String receiver = (String) headers.get(HEADER_RECEIVER); String provider = (String) headers.get(HEADER_PROVIDER); String userId = (String) headers.get(HEADER_USER_ID); @@ -60,7 +49,6 @@ public static SecurityAnalysisResultContext fromMessage(Message message, SecurityAnalysisRunContext runContext = new SecurityAnalysisRunContext( networkUuid, variantId, - contingencyListNames, receiver, provider, parameters, @@ -69,10 +57,4 @@ public static SecurityAnalysisResultContext fromMessage(Message message, ); return new SecurityAnalysisResultContext(resultUuid, runContext); } - - @Override - protected Map getSpecificMsgHeaders(ObjectMapper ignoredObjectMapper) { - return Map.of( - CONTINGENCY_LIST_NAMES_HEADER, String.join(",", getRunContext().getContingencyListNames())); - } } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisRunContext.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisRunContext.java index d70bbf19..25fda4d3 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisRunContext.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisRunContext.java @@ -27,18 +27,15 @@ */ @Getter public class SecurityAnalysisRunContext extends AbstractComputationRunContext { - - private final List contingencyListNames; @Setter private List contingencies; - public SecurityAnalysisRunContext(UUID networkUuid, String variantId, List contingencyListNames, + public SecurityAnalysisRunContext(UUID networkUuid, String variantId, String receiver, String provider, SecurityAnalysisParametersDTO parameters, LoadFlowParametersValues loadFlowParametersValues, ReportInfos reportContext, String userId) { this( networkUuid, variantId, - contingencyListNames, receiver, provider, buildParameters(parameters, loadFlowParametersValues, provider), @@ -47,11 +44,10 @@ public SecurityAnalysisRunContext(UUID networkUuid, String variantId, List contingencyListNames, + public SecurityAnalysisRunContext(UUID networkUuid, String variantId, String receiver, String provider, SecurityAnalysisParametersDTO parameters, ReportInfos reportContext, String userId) { super(networkUuid, variantId, receiver, reportContext, userId, provider, parameters); - this.contingencyListNames = Objects.requireNonNull(contingencyListNames); } private static SecurityAnalysisParametersDTO buildParameters(SecurityAnalysisParametersDTO parameters, diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java index 04eff4bd..a8f4f880 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java @@ -26,7 +26,6 @@ import com.powsybl.network.store.client.PreloadingStrategy; import com.powsybl.security.*; import com.powsybl.security.limitreduction.LimitReduction; -import com.powsybl.ws.commons.LogUtils; import org.gridsuite.computation.service.*; import org.gridsuite.securityanalysis.server.PropertyServerNameProvider; import org.gridsuite.securityanalysis.server.dto.ContingencyInfos; @@ -178,11 +177,13 @@ private LimitReduction createLimitReduction(IdentifiableCriterion voltageLevelCr @Override protected void preRun(SecurityAnalysisRunContext runContext) { - LOGGER.info("Run security analysis on contingency lists: {}", runContext.getContingencyListNames().stream().map(LogUtils::sanitizeParam).toList()); + if (runContext.getParameters().contingencyListsUuids() != null) { + LOGGER.info("Run security analysis on contingency lists: {}", runContext.getParameters().contingencyListsUuids()); //.stream().map(LogUtils::sanitizeParam).toList()); + } List contingencies = observer.observe("contingencies.fetch", runContext, () -> - actionsService.getContingencyList(runContext.getContingencyListNames(), runContext.getNetworkUuid(), runContext.getVariantId()) + actionsService.getContingencyList(runContext.getParameters().contingencyListsUuids(), runContext.getNetworkUuid(), runContext.getVariantId()) ); runContext.setContingencies(contingencies); diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java index 2201d464..c3e8e5fd 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java @@ -22,6 +22,7 @@ import java.util.Comparator; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -36,10 +37,10 @@ public class SecurityAnalysisProviderMock implements SecurityAnalysisProvider { private static final Logger LOGGER = LoggerFactory.getLogger(SecurityAnalysisProviderMock.class); - static final String CONTINGENCY_LIST_NAME = "list1"; - static final String CONTINGENCY_LIST2_NAME = "list2"; - static final String CONTINGENCY_LIST_ERROR_NAME = "listError"; - static final String CONTINGENCY_LIST_NAME_VARIANT = "listVariant"; + static final UUID CONTINGENCY_LIST_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791f"); //"list1"; + static final UUID CONTINGENCY_LIST2_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791g"); //"list2"; + static final UUID CONTINGENCY_LIST_ERROR_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791h"); //"listError"; + static final UUID CONTINGENCY_LIST_NAME_VARIANT = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791i"); //"listVariant"; static final List CONTINGENCIES = List.of( new ContingencyInfos(new Contingency("l1", new BranchContingency("l1")), Set.of("wrongId1, wrongId2"), Set.of()), diff --git a/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java b/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java index f3ba6b34..b40c39c1 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java @@ -55,10 +55,10 @@ class ActionsServiceTest { private static final String VARIANT_ID = "variant_id"; - private static final String LIST_NAME = "myList"; - private static final String LIST_NAME_VARIANT = "myListVariant"; + private static final UUID LIST_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791j"); //"myList"; + private static final UUID LIST_NAME_VARIANT = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791k"); //"myListVariant"; - private static final String VERY_LARGE_LIST_NAME = "veryLargelist"; + private static final UUID VERY_LARGE_LIST_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791l"); //"veryLargelist"; public static final String WRONG_ID = "wrongID"; private static final ContingencyInfos CONTINGENCY = new ContingencyInfos(new Contingency("c1", new BranchContingency("b1")), Set.of(WRONG_ID), Set.of()); From 357b562503f3504315240e708751b7f346e3bade Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Fri, 6 Feb 2026 18:51:15 +0100 Subject: [PATCH 02/11] add several contingencies for each contingencyList + get contingencies name from directory server --- .../server/dto/ContingencyListsDTO.java | 36 ----------- .../dto/ParametersContingenciesDTO.java | 20 ++++++ .../dto/ParametersContingencyListDTO.java | 24 +++++++ .../dto/SecurityAnalysisParametersDTO.java | 2 +- .../dto/SecurityAnalysisParametersValues.java | 2 +- .../entities/ContingencyListsEmbeddable.java | 34 ---------- .../ParametersContingencyListEntity.java | 49 +++++++++++++++ .../SecurityAnalysisParametersEntity.java | 39 +++++++++--- .../server/service/DirectoryService.java | 63 +++++++++++++++++++ .../ParametersContingenciesService.java | 38 +++++++++++ .../SecurityAnalysisParametersService.java | 16 +++-- .../SecurityAnalysisWorkerService.java | 6 +- src/main/resources/application-local.yaml | 2 + 13 files changed, 242 insertions(+), 89 deletions(-) delete mode 100644 src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java delete mode 100644 src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyListsEmbeddable.java create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java deleted file mode 100644 index 0321e6a2..00000000 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/ContingencyListsDTO.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2025, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.gridsuite.securityanalysis.server.dto; - -import lombok.*; -import org.gridsuite.securityanalysis.server.entities.ContingencyListsEmbeddable; - -import java.util.UUID; - -/** - * @author Caroline Jeandat {@literal } - */ -@Data -@Builder -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class ContingencyListsDTO { - private UUID id; - private String name; - private boolean activated; - - public ContingencyListsDTO(ContingencyListsEmbeddable contingencyListsEmbeddable) { - this.id = contingencyListsEmbeddable.getId(); - this.name = contingencyListsEmbeddable.getName(); - this.activated = contingencyListsEmbeddable.isActivated(); - } - - public ContingencyListsEmbeddable toEmbeddable() { - return new ContingencyListsEmbeddable(this); - } -} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java new file mode 100644 index 00000000..8e17dafc --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java @@ -0,0 +1,20 @@ +package org.gridsuite.securityanalysis.server.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +/** + * @author Caroline Jeandat {@literal } + */ +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ParametersContingenciesDTO { + UUID id; + String name; +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java new file mode 100644 index 00000000..4b1e9960 --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server.dto; +import lombok.*; + +import java.util.List; + +/** + * @author Caroline Jeandat {@literal } + */ +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class ParametersContingencyListDTO { + List contingencies; + String description; + boolean activated; +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java index ff68e8cd..24b68301 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersDTO.java @@ -15,6 +15,6 @@ @Builder public record SecurityAnalysisParametersDTO( SecurityAnalysisParameters securityAnalysisParameters, - List contingencyListsUuids, + List contingencyListUuids, List> limitReductions ) { } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java index 07522b71..20d48738 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java @@ -36,7 +36,7 @@ public class SecurityAnalysisParametersValues { private double flowProportionalThreshold; - private List contingencyLists; + private List contingencyLists; private List limitReductions; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyListsEmbeddable.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyListsEmbeddable.java deleted file mode 100644 index e2c7a064..00000000 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyListsEmbeddable.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2025, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.gridsuite.securityanalysis.server.entities; - -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.gridsuite.securityanalysis.server.dto.ContingencyListsDTO; - -import java.util.UUID; - -/** - * @author Caroline Jeandat {@literal } - */ -@Getter -@AllArgsConstructor -@NoArgsConstructor -@Embeddable -public class ContingencyListsEmbeddable { - private UUID id; - private String name; - private boolean activated; - - public ContingencyListsEmbeddable(ContingencyListsDTO contingencyListsDTO) { - this.id = contingencyListsDTO.getId(); - this.name = contingencyListsDTO.getName(); - this.activated = contingencyListsDTO.isActivated(); - } -} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java new file mode 100644 index 00000000..b5c69761 --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java @@ -0,0 +1,49 @@ +package org.gridsuite.securityanalysis.server.entities; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; +import java.util.UUID; + +/** + * @author Caroline Jeandat {@literal } + */ +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "parameters_contingency_list", indexes = {@Index(name = "idx_security_analysis_parameters_id", columnList = "security_analysis_parameters_id")}) +public class ParametersContingencyListEntity { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Column(name = "contingency_list_id") + private UUID id; + + @ElementCollection + @CollectionTable( + name = "parameters_contingency_list_contingencies", + joinColumns = @JoinColumn(name = "contingency_list_id") + ) + @Column(name = "contingencies_id") + private List contingenciesIds; + + @Column(name = "description") + private String description; + + @Column(name = "activated") + private boolean activated; + + @ManyToOne + @JoinColumn(name = "security_analysis_parameters_id") + private SecurityAnalysisParametersEntity securityAnalysisParameters; + + public ParametersContingencyListEntity(List contingenciesIds, String description, boolean activated) { + this.contingenciesIds = contingenciesIds; + this.description = description; + this.activated = activated; + } +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java index eb8b76a0..ecc287d5 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java @@ -8,6 +8,8 @@ import jakarta.persistence.*; import lombok.*; +import org.gridsuite.securityanalysis.server.dto.ParametersContingenciesDTO; +import org.gridsuite.securityanalysis.server.dto.ParametersContingencyListDTO; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersValues; import org.springframework.lang.Nullable; @@ -55,12 +57,10 @@ public SecurityAnalysisParametersEntity(SecurityAnalysisParametersValues securit @Column(name = "flowProportionalThreshold") private double flowProportionalThreshold; - @ElementCollection - @CollectionTable( - name = "contingency_lists", - joinColumns = @JoinColumn(name = "security_analysis_parameters_id") - ) - private List contingencyLists; + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "securityAnalysisParameters") + @OrderColumn(name = "index") + @Builder.Default + private List contingencyLists = new ArrayList<>(); @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "security_analysis_parameters_id", foreignKey = @ForeignKey(name = "securityAnalysisParametersEntity_limitReductions_fk")) @@ -72,8 +72,8 @@ public List getActivatedContingencyListUuids() { return List.of(); } return this.contingencyLists.stream() - .filter(ContingencyListsEmbeddable::isActivated) - .map(ContingencyListsEmbeddable::getId) + .filter(ParametersContingencyListEntity::isActivated) + .flatMap(contingencyList -> contingencyList.getContingenciesIds().stream()) .toList(); } @@ -92,10 +92,30 @@ private void assignAttributes(SecurityAnalysisParametersValues securityAnalysisP this.highVoltageProportionalThreshold = securityAnalysisParametersValues.getHighVoltageProportionalThreshold(); this.lowVoltageAbsoluteThreshold = securityAnalysisParametersValues.getLowVoltageAbsoluteThreshold(); this.lowVoltageProportionalThreshold = securityAnalysisParametersValues.getLowVoltageProportionalThreshold(); - this.contingencyLists = securityAnalysisParametersValues.getContingencyLists().stream().map(ContingencyListsEmbeddable::new).toList(); + assignContingencyLists(securityAnalysisParametersValues.getContingencyLists()); assignLimitReductions(securityAnalysisParametersValues.getLimitReductionsValues()); } + private void assignContingencyLists(List contingencyListsDTO) { + if (contingencyListsDTO == null) { + return; + } + + List entities = contingencyListsDTO.stream() + .map(dto -> { + ParametersContingencyListEntity entity = new ParametersContingencyListEntity( + dto.getContingencies().stream().map(ParametersContingenciesDTO::getId).toList(), + dto.getDescription(), + dto.isActivated() + ); + entity.setSecurityAnalysisParameters(this); + return entity; + }) + .toList(); + contingencyLists.clear(); + contingencyLists.addAll(entities); + } + private void assignLimitReductions(@Nullable List> values) { if (values == null) { return; @@ -113,4 +133,3 @@ public void updateProvider(String provider) { this.provider = provider; } } - diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java new file mode 100644 index 00000000..f2d9ef56 --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java @@ -0,0 +1,63 @@ +package org.gridsuite.securityanalysis.server.service; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.util.*; + +/** + * @author Caroline Jeandat {@literal } + */ +@Service +public class DirectoryService { + static final String DIRECTORY_API_VERSION = "v1"; + + private static final String DELIMITER = "/"; + + private String baseUri; + + private RestTemplate restTemplate; + + public void setDirectoryServiceBaseUri(String baseUri) { + this.baseUri = baseUri; + } + + public DirectoryService( + @Value("${gridsuite.services.directory-server.base-uri:http://directory-server}") String baseUri, + RestTemplate restTemplate) { + this.baseUri = baseUri; + this.restTemplate = restTemplate; + } + + public String getContingenciesName(UUID contingenciesId) { + Objects.requireNonNull(contingenciesId); + + URI path = UriComponentsBuilder + .fromPath(DELIMITER + DIRECTORY_API_VERSION + "/elements/{elementUuid}") + .buildAndExpand(contingenciesId) + .toUri(); + + try { + ResponseEntity> response = + restTemplate.exchange( + baseUri + path, + HttpMethod.GET, + null, + new ParameterizedTypeReference<>() { } + ); + + Map responseBody = response.getBody(); + return responseBody != null ? (String) responseBody.get("elementName") : null; + + } catch (HttpClientErrorException.NotFound e) { + return null; + } + } +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java new file mode 100644 index 00000000..ecfadef8 --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java @@ -0,0 +1,38 @@ +package org.gridsuite.securityanalysis.server.service; + +import org.gridsuite.securityanalysis.server.dto.ParametersContingenciesDTO; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +/** + * @author Caroline Jeandat {@literal } + */ +@Service +public class ParametersContingenciesService { + + private final DirectoryService directoryService; + + public ParametersContingenciesService(DirectoryService directoryService) { + this.directoryService = directoryService; + } + + public List toDTO(List contingenciesIds) { + return contingenciesIds == null ? null : + contingenciesIds.stream() + .map(id -> new ParametersContingenciesDTO(id, getContingenciesName(id))) + .toList(); + } + + public List toUUIDs(List contingenciesDTOs) { + return contingenciesDTOs == null ? null : + contingenciesDTOs.stream() + .map(ParametersContingenciesDTO::getId) + .toList(); + } + + private String getContingenciesName(UUID contingencyId) { + return directoryService.getContingenciesName(contingencyId); + } +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java index e4811486..4c6fee5d 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java @@ -32,6 +32,8 @@ public class SecurityAnalysisParametersService { private final LoadFlowService loadFlowService; + private final ParametersContingenciesService parametersContingenciesService; + private final String defaultProvider; private final LimitReductionService limitReductionService; @@ -41,12 +43,13 @@ public class SecurityAnalysisParametersService { private static final double DEFAULT_HIGH_VOLTAGE_PROPORTIONAL_THRESHOLD = 0.01; // meaning 1.0 % private static final double DEFAULT_LOW_VOLTAGE_ABSOLUTE_THRESHOLD = 1.0; // 1.0 kV private static final double DEFAULT_HIGH_VOLTAGE_ABSOLUTE_THRESHOLD = 1.0; // 1.0 kV - private static final List DEFAULT_CONTINGENCY_LISTS = new ArrayList<>(); + private static final List DEFAULT_CONTINGENCY_LISTS = new ArrayList<>(); - public SecurityAnalysisParametersService(@NonNull SecurityAnalysisParametersRepository securityAnalysisParametersRepository, @NonNull LoadFlowService loadFlowService, + public SecurityAnalysisParametersService(@NonNull SecurityAnalysisParametersRepository securityAnalysisParametersRepository, @NonNull LoadFlowService loadFlowService, @NonNull ParametersContingenciesService parametersContingenciesService, @Value("${security-analysis.default-provider}") String defaultProvider, @NonNull LimitReductionService limitReductionService) { this.securityAnalysisParametersRepository = Objects.requireNonNull(securityAnalysisParametersRepository); this.loadFlowService = loadFlowService; + this.parametersContingenciesService = parametersContingenciesService; this.defaultProvider = defaultProvider; this.limitReductionService = limitReductionService; } @@ -96,7 +99,7 @@ public SecurityAnalysisParametersDTO toSecurityAnalysisParameters(SecurityAnalys } return SecurityAnalysisParametersDTO.builder() .securityAnalysisParameters(securityAnalysisParameters) - .contingencyListsUuids(activatedContingencyListUuids) + .contingencyListUuids(activatedContingencyListUuids) .limitReductions(limitReductions) .build(); } @@ -109,7 +112,12 @@ public SecurityAnalysisParametersValues toSecurityAnalysisParametersValues(Secur .highVoltageProportionalThreshold(entity.getHighVoltageProportionalThreshold()) .lowVoltageAbsoluteThreshold(entity.getLowVoltageAbsoluteThreshold()) .lowVoltageProportionalThreshold(entity.getLowVoltageProportionalThreshold()) - .contingencyLists(entity.getContingencyLists().stream().map(ContingencyListsDTO::new).toList()) + .contingencyLists(entity.getContingencyLists().stream() + .map(c -> new ParametersContingencyListDTO( + parametersContingenciesService.toDTO(c.getContingenciesIds()), + c.getDescription(), + c.isActivated())) + .toList()) .limitReductions(getLimitReductionsForProvider(entity).orElse(null)) .build(); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java index a8f4f880..d85b3a42 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java @@ -177,13 +177,13 @@ private LimitReduction createLimitReduction(IdentifiableCriterion voltageLevelCr @Override protected void preRun(SecurityAnalysisRunContext runContext) { - if (runContext.getParameters().contingencyListsUuids() != null) { - LOGGER.info("Run security analysis on contingency lists: {}", runContext.getParameters().contingencyListsUuids()); //.stream().map(LogUtils::sanitizeParam).toList()); + if (runContext.getParameters().contingencyListUuids() != null) { + LOGGER.info("Run security analysis on contingency lists: {}", runContext.getParameters().contingencyListUuids()); //.stream().map(LogUtils::sanitizeParam).toList()); } List contingencies = observer.observe("contingencies.fetch", runContext, () -> - actionsService.getContingencyList(runContext.getParameters().contingencyListsUuids(), runContext.getNetworkUuid(), runContext.getVariantId()) + actionsService.getContingencyList(runContext.getParameters().contingencyListUuids(), runContext.getNetworkUuid(), runContext.getVariantId()) ); runContext.setContingencies(contingencies); diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index a249a4ef..dda0a5f9 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -22,3 +22,5 @@ gridsuite: base-uri: http://localhost:5028 loadflow-server: base-uri: http://localhost:5008 + directory-server: + base-uri: http://localhost:5026 From c3f8d597bd91ec86f275a87b696e6468b7093833 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Mon, 9 Feb 2026 09:02:48 +0100 Subject: [PATCH 03/11] add changelog --- .../changesets/changelog_20260209T074419Z.xml | 33 +++++++++++++++++++ .../db/changelog/db.changelog-master.yaml | 3 ++ 2 files changed, 36 insertions(+) create mode 100644 src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml diff --git a/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml b/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml new file mode 100644 index 00000000..b27f509a --- /dev/null +++ b/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 2dfde1d1..17f61bcc 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -54,3 +54,6 @@ databaseChangeLog: - include: file: changesets/changelog_20260116T110615Z.xml relativeToChangelogFile: true +# - include: +# file: changesets/changelog_20260209T074419Z.xml +# relativeToChangelogFile: true From c529e1f66e888e1c7c627f44d6cc654f43677772 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Mon, 9 Feb 2026 09:03:16 +0100 Subject: [PATCH 04/11] add changelog --- src/main/resources/db/changelog/db.changelog-master.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 17f61bcc..7442be2f 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -54,6 +54,6 @@ databaseChangeLog: - include: file: changesets/changelog_20260116T110615Z.xml relativeToChangelogFile: true -# - include: -# file: changesets/changelog_20260209T074419Z.xml -# relativeToChangelogFile: true + - include: + file: changesets/changelog_20260209T074419Z.xml + relativeToChangelogFile: true From 40863e673d855c49696054bb4cdd33a289fae745 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Mon, 9 Feb 2026 16:12:21 +0100 Subject: [PATCH 05/11] fix index name --- .../server/entities/ParametersContingencyListEntity.java | 2 +- .../db/changelog/changesets/changelog_20260209T074419Z.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java index b5c69761..1d1c7afd 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java @@ -15,7 +15,7 @@ @Setter @NoArgsConstructor @Entity -@Table(name = "parameters_contingency_list", indexes = {@Index(name = "idx_security_analysis_parameters_id", columnList = "security_analysis_parameters_id")}) +@Table(name = "parameters_contingency_list", indexes = {@Index(name = "idx_security_analysis_parameters_id_contingency_lists", columnList = "security_analysis_parameters_id")}) public class ParametersContingencyListEntity { @Id diff --git a/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml b/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml index b27f509a..b78fb8f7 100644 --- a/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml +++ b/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml @@ -20,7 +20,7 @@ - + From eea3192b753944fe0c8d486aeccdd4069d1dbbed Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Wed, 11 Feb 2026 15:08:26 +0100 Subject: [PATCH 06/11] fix --- .../SecurityAnalysisParametersEntity.java | 11 +++++++---- .../service/SecurityAnalysisWorkerService.java | 18 +++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java index ecc287d5..c37c913c 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java @@ -59,8 +59,7 @@ public SecurityAnalysisParametersEntity(SecurityAnalysisParametersValues securit @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "securityAnalysisParameters") @OrderColumn(name = "index") - @Builder.Default - private List contingencyLists = new ArrayList<>(); + private List contingencyLists; // = new ArrayList<>(); @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "security_analysis_parameters_id", foreignKey = @ForeignKey(name = "securityAnalysisParametersEntity_limitReductions_fk")) @@ -112,8 +111,12 @@ private void assignContingencyLists(List contingen return entity; }) .toList(); - contingencyLists.clear(); - contingencyLists.addAll(entities); + if (contingencyLists == null) { + contingencyLists = entities; + } else { + contingencyLists.clear(); + contingencyLists.addAll(entities); + } } private void assignLimitReductions(@Nullable List> values) { diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java index d85b3a42..503cf973 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java @@ -40,6 +40,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -178,15 +179,18 @@ private LimitReduction createLimitReduction(IdentifiableCriterion voltageLevelCr @Override protected void preRun(SecurityAnalysisRunContext runContext) { if (runContext.getParameters().contingencyListUuids() != null) { - LOGGER.info("Run security analysis on contingency lists: {}", runContext.getParameters().contingencyListUuids()); //.stream().map(LogUtils::sanitizeParam).toList()); + LOGGER.info("Run security analysis on contingency lists: {}", runContext.getParameters().contingencyListUuids()); } - List contingencies = observer.observe("contingencies.fetch", runContext, - () -> - actionsService.getContingencyList(runContext.getParameters().contingencyListUuids(), runContext.getNetworkUuid(), runContext.getVariantId()) - ); - - runContext.setContingencies(contingencies); + try { + List contingencies = observer.observe("contingencies.fetch", runContext, + () -> + actionsService.getContingencyList(runContext.getParameters().contingencyListUuids(), runContext.getNetworkUuid(), runContext.getVariantId()) + ); + runContext.setContingencies(contingencies); + } catch (IllegalArgumentException e) { + throw new InvalidParameterException("No contingency list found in parameters to run the analysis"); + } } @Override From 307517678baa1367fed129d0073c1d79d88f03e6 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Fri, 13 Feb 2026 17:51:33 +0100 Subject: [PATCH 07/11] address review comments --- .../SecurityAnalysisParametersController.java | 12 +++-- .../server/dto/IdNameInfos.java | 26 +++++++++ .../dto/ParametersContingenciesDTO.java | 20 ------- .../dto/ParametersContingencyListDTO.java | 8 +-- .../ParametersContingencyListEntity.java | 23 +++++--- .../SecurityAnalysisParametersEntity.java | 11 ++-- .../server/service/DirectoryService.java | 53 ++++++++++++------- .../ParametersContingenciesService.java | 38 ------------- .../SecurityAnalysisParametersService.java | 45 ++++++++++------ .../SecurityAnalysisControllerTest.java | 32 +++++------ .../server/SecurityAnalysisProviderMock.java | 8 +-- .../server/service/ActionsServiceTest.java | 26 ++++----- 12 files changed, 155 insertions(+), 147 deletions(-) create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/dto/IdNameInfos.java delete mode 100644 src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java delete mode 100644 src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java diff --git a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java index 57a5a924..4ea04323 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java @@ -21,6 +21,8 @@ import java.util.List; import java.util.UUID; +import static org.gridsuite.computation.service.NotificationService.HEADER_USER_ID; + /** * @author Abdelsalem Hedhili */ @@ -57,8 +59,9 @@ public ResponseEntity createDefaultParameters() { @ApiResponse(responseCode = "200", description = "parameters were duplicated"), @ApiResponse(responseCode = "404", description = "source parameters were not found")}) public ResponseEntity duplicateParameters( - @Parameter(description = "source parameters UUID") @RequestParam(name = "duplicateFrom") UUID sourceParametersUuid) { - return parametersService.duplicateParameters(sourceParametersUuid).map(duplicatedParametersUuid -> ResponseEntity.ok() + @Parameter(description = "source parameters UUID") @RequestParam(name = "duplicateFrom") UUID sourceParametersUuid, + @RequestHeader(HEADER_USER_ID) String userId) { + return parametersService.duplicateParameters(sourceParametersUuid, userId).map(duplicatedParametersUuid -> ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .body(duplicatedParametersUuid)) .orElse(ResponseEntity.notFound().build()); @@ -70,8 +73,9 @@ public ResponseEntity duplicateParameters( @ApiResponse(responseCode = "200", description = "parameters were returned"), @ApiResponse(responseCode = "404", description = "parameters were not found")}) public ResponseEntity getParameters( - @Parameter(description = "parameters UUID") @PathVariable(value = "uuid") UUID parametersUuid) { - return parametersService.getParameters(parametersUuid) + @Parameter(description = "parameters UUID") @PathVariable(value = "uuid") UUID parametersUuid, + @RequestHeader(HEADER_USER_ID) String userId) { + return parametersService.getParameters(parametersUuid, userId) .map(parametersValues -> ResponseEntity.ok().body(parametersValues)) .orElse(ResponseEntity.notFound().build()); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/IdNameInfos.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/IdNameInfos.java new file mode 100644 index 00000000..722ed24a --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/IdNameInfos.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +/** + * @author Caroline Jeandat {@literal } + */ +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class IdNameInfos { + private UUID id; + private String name; +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java deleted file mode 100644 index 8e17dafc..00000000 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingenciesDTO.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.gridsuite.securityanalysis.server.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.UUID; - -/** - * @author Caroline Jeandat {@literal } - */ -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -public class ParametersContingenciesDTO { - UUID id; - String name; -} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java index 4b1e9960..de5cc980 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2025, RTE (http://www.rte-france.com) + * Copyright (c) 2026, RTE (http://www.rte-france.com) * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -18,7 +18,7 @@ @Getter @Setter public class ParametersContingencyListDTO { - List contingencies; - String description; - boolean activated; + private List contingencies; + private String description; + private boolean activated; } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java index 1d1c7afd..a8c8816b 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java @@ -1,3 +1,9 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.gridsuite.securityanalysis.server.entities; import jakarta.persistence.*; @@ -15,21 +21,22 @@ @Setter @NoArgsConstructor @Entity -@Table(name = "parameters_contingency_list", indexes = {@Index(name = "idx_security_analysis_parameters_id_contingency_lists", columnList = "security_analysis_parameters_id")}) +@Table(name = "parameters_contingency_lists", indexes = {@Index(name = "idx_parameters_contingency_lists_security_analysis_parameters_id", columnList = "security_analysis_parameters_id")}) public class ParametersContingencyListEntity { @Id @GeneratedValue(strategy = GenerationType.UUID) - @Column(name = "contingency_list_id") + @Column(name = "id") private UUID id; @ElementCollection @CollectionTable( - name = "parameters_contingency_list_contingencies", - joinColumns = @JoinColumn(name = "contingency_list_id") + name = "parameters_contingency_lists_contingency_list", + joinColumns = @JoinColumn(name = "parameters_contingency_lists_id"), + foreignKey = @ForeignKey(name = "parameters_contingency_lists_id_fk") ) - @Column(name = "contingencies_id") - private List contingenciesIds; + @Column(name = "contingency_list_id") + private List contingencyListIds; @Column(name = "description") private String description; @@ -41,8 +48,8 @@ public class ParametersContingencyListEntity { @JoinColumn(name = "security_analysis_parameters_id") private SecurityAnalysisParametersEntity securityAnalysisParameters; - public ParametersContingencyListEntity(List contingenciesIds, String description, boolean activated) { - this.contingenciesIds = contingenciesIds; + public ParametersContingencyListEntity(List contingencyListIds, String description, boolean activated) { + this.contingencyListIds = contingencyListIds; this.description = description; this.activated = activated; } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java index c37c913c..82c46132 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java @@ -8,7 +8,7 @@ import jakarta.persistence.*; import lombok.*; -import org.gridsuite.securityanalysis.server.dto.ParametersContingenciesDTO; +import org.gridsuite.securityanalysis.server.dto.IdNameInfos; import org.gridsuite.securityanalysis.server.dto.ParametersContingencyListDTO; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersValues; import org.springframework.lang.Nullable; @@ -59,7 +59,7 @@ public SecurityAnalysisParametersEntity(SecurityAnalysisParametersValues securit @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "securityAnalysisParameters") @OrderColumn(name = "index") - private List contingencyLists; // = new ArrayList<>(); + private List contingencyLists; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "security_analysis_parameters_id", foreignKey = @ForeignKey(name = "securityAnalysisParametersEntity_limitReductions_fk")) @@ -72,7 +72,7 @@ public List getActivatedContingencyListUuids() { } return this.contingencyLists.stream() .filter(ParametersContingencyListEntity::isActivated) - .flatMap(contingencyList -> contingencyList.getContingenciesIds().stream()) + .flatMap(contingencyList -> contingencyList.getContingencyListIds().stream()) .toList(); } @@ -102,8 +102,11 @@ private void assignContingencyLists(List contingen List entities = contingencyListsDTO.stream() .map(dto -> { + List contingencyListIds = dto.getContingencies().stream() + .map(IdNameInfos::getId) + .toList(); ParametersContingencyListEntity entity = new ParametersContingencyListEntity( - dto.getContingencies().stream().map(ParametersContingenciesDTO::getId).toList(), + contingencyListIds, dto.getDescription(), dto.isActivated() ); diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java index f2d9ef56..cdba6e1a 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java @@ -1,9 +1,14 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.gridsuite.securityanalysis.server.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; @@ -11,6 +16,9 @@ import java.net.URI; import java.util.*; +import java.util.stream.Collectors; + +import static org.gridsuite.computation.service.NotificationService.HEADER_USER_ID; /** * @author Caroline Jeandat {@literal } @@ -18,16 +26,9 @@ @Service public class DirectoryService { static final String DIRECTORY_API_VERSION = "v1"; - private static final String DELIMITER = "/"; - - private String baseUri; - - private RestTemplate restTemplate; - - public void setDirectoryServiceBaseUri(String baseUri) { - this.baseUri = baseUri; - } + private final String baseUri; + private final RestTemplate restTemplate; public DirectoryService( @Value("${gridsuite.services.directory-server.base-uri:http://directory-server}") String baseUri, @@ -36,28 +37,40 @@ public DirectoryService( this.restTemplate = restTemplate; } - public String getContingenciesName(UUID contingenciesId) { - Objects.requireNonNull(contingenciesId); + public Map getElementNames(List elementUuids, String userId) { + Objects.requireNonNull(elementUuids); + + if (elementUuids.isEmpty()) { + return Map.of(); + } URI path = UriComponentsBuilder - .fromPath(DELIMITER + DIRECTORY_API_VERSION + "/elements/{elementUuid}") - .buildAndExpand(contingenciesId) + .fromPath(DELIMITER + DIRECTORY_API_VERSION + "/elements") + .queryParam("ids", elementUuids) + .build() .toUri(); + HttpHeaders headers = new HttpHeaders(); + headers.set(HEADER_USER_ID, userId); + headers.setContentType(MediaType.APPLICATION_JSON); + try { - ResponseEntity> response = + ResponseEntity>> response = restTemplate.exchange( baseUri + path, HttpMethod.GET, - null, + new HttpEntity<>(headers), new ParameterizedTypeReference<>() { } ); - Map responseBody = response.getBody(); - return responseBody != null ? (String) responseBody.get("elementName") : null; + List> responseBody = response.getBody(); + return responseBody != null ? responseBody.stream().collect(Collectors.toMap( + e -> UUID.fromString((String) e.get("elementUuid")), + e -> (String) e.get("elementName") + )) : Map.of(); } catch (HttpClientErrorException.NotFound e) { - return null; + return Map.of(); } } } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java deleted file mode 100644 index ecfadef8..00000000 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/ParametersContingenciesService.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.gridsuite.securityanalysis.server.service; - -import org.gridsuite.securityanalysis.server.dto.ParametersContingenciesDTO; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.UUID; - -/** - * @author Caroline Jeandat {@literal } - */ -@Service -public class ParametersContingenciesService { - - private final DirectoryService directoryService; - - public ParametersContingenciesService(DirectoryService directoryService) { - this.directoryService = directoryService; - } - - public List toDTO(List contingenciesIds) { - return contingenciesIds == null ? null : - contingenciesIds.stream() - .map(id -> new ParametersContingenciesDTO(id, getContingenciesName(id))) - .toList(); - } - - public List toUUIDs(List contingenciesDTOs) { - return contingenciesDTOs == null ? null : - contingenciesDTOs.stream() - .map(ParametersContingenciesDTO::getId) - .toList(); - } - - private String getContingenciesName(UUID contingencyId) { - return directoryService.getContingenciesName(contingencyId); - } -} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java index 4c6fee5d..45b6570e 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java @@ -32,12 +32,12 @@ public class SecurityAnalysisParametersService { private final LoadFlowService loadFlowService; - private final ParametersContingenciesService parametersContingenciesService; - private final String defaultProvider; private final LimitReductionService limitReductionService; + private final DirectoryService directoryService; + private static final double DEFAULT_FLOW_PROPORTIONAL_THRESHOLD = 0.1; // meaning 10.0 % private static final double DEFAULT_LOW_VOLTAGE_PROPORTIONAL_THRESHOLD = 0.01; // meaning 1.0 % private static final double DEFAULT_HIGH_VOLTAGE_PROPORTIONAL_THRESHOLD = 0.01; // meaning 1.0 % @@ -45,13 +45,13 @@ public class SecurityAnalysisParametersService { private static final double DEFAULT_HIGH_VOLTAGE_ABSOLUTE_THRESHOLD = 1.0; // 1.0 kV private static final List DEFAULT_CONTINGENCY_LISTS = new ArrayList<>(); - public SecurityAnalysisParametersService(@NonNull SecurityAnalysisParametersRepository securityAnalysisParametersRepository, @NonNull LoadFlowService loadFlowService, @NonNull ParametersContingenciesService parametersContingenciesService, - @Value("${security-analysis.default-provider}") String defaultProvider, @NonNull LimitReductionService limitReductionService) { + public SecurityAnalysisParametersService(@NonNull SecurityAnalysisParametersRepository securityAnalysisParametersRepository, @NonNull LoadFlowService loadFlowService, + @Value("${security-analysis.default-provider}") String defaultProvider, @NonNull LimitReductionService limitReductionService, @NonNull DirectoryService directoryService) { this.securityAnalysisParametersRepository = Objects.requireNonNull(securityAnalysisParametersRepository); this.loadFlowService = loadFlowService; - this.parametersContingenciesService = parametersContingenciesService; this.defaultProvider = defaultProvider; this.limitReductionService = limitReductionService; + this.directoryService = directoryService; } @Transactional(readOnly = true) @@ -104,7 +104,7 @@ public SecurityAnalysisParametersDTO toSecurityAnalysisParameters(SecurityAnalys .build(); } - public SecurityAnalysisParametersValues toSecurityAnalysisParametersValues(SecurityAnalysisParametersEntity entity) { + public SecurityAnalysisParametersValues toSecurityAnalysisParametersValues(SecurityAnalysisParametersEntity entity, String userId) { return SecurityAnalysisParametersValues.builder() .provider(entity.getProvider()) .flowProportionalThreshold(entity.getFlowProportionalThreshold()) @@ -112,16 +112,29 @@ public SecurityAnalysisParametersValues toSecurityAnalysisParametersValues(Secur .highVoltageProportionalThreshold(entity.getHighVoltageProportionalThreshold()) .lowVoltageAbsoluteThreshold(entity.getLowVoltageAbsoluteThreshold()) .lowVoltageProportionalThreshold(entity.getLowVoltageProportionalThreshold()) - .contingencyLists(entity.getContingencyLists().stream() - .map(c -> new ParametersContingencyListDTO( - parametersContingenciesService.toDTO(c.getContingenciesIds()), - c.getDescription(), - c.isActivated())) - .toList()) + .contingencyLists(Optional.of( + entity.getContingencyLists().stream() + .map(c -> new ParametersContingencyListDTO( + contingenciesIdsToDTOs(c.getContingencyListIds(), userId), + c.getDescription(), + c.isActivated())) + .toList()) + .filter(list -> !list.isEmpty()) // if empty list return null + .orElse(null)) .limitReductions(getLimitReductionsForProvider(entity).orElse(null)) .build(); } + private List contingenciesIdsToDTOs(List contingenciesIds, String userId) { + if (contingenciesIds == null) { + return null; + } + Map contingenciesInfos = directoryService.getElementNames(contingenciesIds, userId); + return contingenciesIds.stream() + .map(id -> new IdNameInfos(id, contingenciesInfos.get(id))) + .toList(); + } + private Optional> getLimitReductionsForProvider(SecurityAnalysisParametersEntity entity) { // Only for some providers if (!limitReductionService.getProviders().contains(entity.getProvider())) { @@ -155,9 +168,9 @@ public SecurityAnalysisParametersValues getDefaultSecurityAnalysisParametersValu } @Transactional(readOnly = true) - public Optional getParameters(UUID parametersUuid) { + public Optional getParameters(UUID parametersUuid, String userId) { return securityAnalysisParametersRepository.findById(parametersUuid) - .map(this::toSecurityAnalysisParametersValues); + .map(entity -> toSecurityAnalysisParametersValues(entity, userId)); } public UUID createParameters(SecurityAnalysisParametersValues securityAnalysisParametersValues) { @@ -169,8 +182,8 @@ public UUID createDefaultParameters() { } @Transactional - public Optional duplicateParameters(UUID sourceParametersUuid) { - Optional securityAnalysisParametersValuesOptional = securityAnalysisParametersRepository.findById(sourceParametersUuid).map(this::toSecurityAnalysisParametersValues); + public Optional duplicateParameters(UUID sourceParametersUuid, String userId) { + Optional securityAnalysisParametersValuesOptional = securityAnalysisParametersRepository.findById(sourceParametersUuid).map(entity -> toSecurityAnalysisParametersValues(entity, userId)); return securityAnalysisParametersValuesOptional.map(parametersValues -> securityAnalysisParametersRepository.save(new SecurityAnalysisParametersEntity(parametersValues)).getId()); } diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java index efeb8f36..ca5c2fb7 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java @@ -239,7 +239,7 @@ void tearDown() throws Exception { } private void simpleRunRequest(SecurityAnalysisParametersInfos lfParams) throws Exception { - MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME_VARIANT + "&variantId=" + VARIANT_3_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) + MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID_VARIANT + "&variantId=" + VARIANT_3_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) .contentType(MediaType.APPLICATION_JSON) .header(HEADER_USER_ID, "testUserId") .content(mapper.writeValueAsString(lfParams))) @@ -273,7 +273,7 @@ void runTest() throws Exception { String resultAsString; // run with specific variant - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME_VARIANT + "&variantId=" + VARIANT_3_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID_VARIANT + "&variantId=" + VARIANT_3_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( @@ -286,7 +286,7 @@ void runTest() throws Exception { assertThat(RESULT_VARIANT, new MatcherJson<>(mapper, securityAnalysisResult)); // run with implicit initial variant - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + "&loadFlowParametersUuid=" + UUID.randomUUID()) + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( @@ -305,7 +305,7 @@ void runAndSaveTest() throws Exception { String resultAsString; SQLStatementCountValidator.reset(); - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) @@ -371,7 +371,7 @@ void testDeterministicResults() throws Exception { MvcResult mvcResult; String resultAsString; SQLStatementCountValidator.reset(); - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) @@ -591,8 +591,8 @@ private void verifyNmkContingrnciesResultLocationIds(List void runWithTwoLists() throws Exception { MvcResult mvcResult; String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + - "&contingencyListName=" + CONTINGENCY_LIST2_NAME + "&variantId=" + VARIANT_1_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + + "&contingencyListName=" + CONTINGENCY_LIST2_UUID + "&variantId=" + VARIANT_1_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) .contentType(MediaType.APPLICATION_JSON) .header(HEADER_USER_ID, "testUserId")) .andExpectAll( @@ -609,7 +609,7 @@ void deleteResultsTest() throws Exception { MvcResult mvcResult; String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + "&loadFlowParametersUuid=" + UUID.randomUUID()) + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( @@ -654,7 +654,7 @@ void testStatus() throws Exception { assertEquals(SecurityAnalysisStatus.NOT_DONE, securityAnalysisStatus); // running computation to create result - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) @@ -701,7 +701,7 @@ void stopTest() throws Exception { MvcResult mvcResult; String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_STOP_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_STOP_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&receiver=me&variantId=" + VARIANT_TO_STOP_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) @@ -749,10 +749,10 @@ void runTestWithError() throws Exception { MvcResult mvcResult; String resultAsString; - given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_ERROR_NAME), NETWORK_UUID, VARIANT_1_ID)) + given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_ERROR_UUID), NETWORK_UUID, VARIANT_1_ID)) .willThrow(new RuntimeException(ERROR_MESSAGE)); - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_ERROR_NAME + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_ERROR_UUID + "&receiver=me&variantId=" + VARIANT_1_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) @@ -777,7 +777,7 @@ void runWithReportTest() throws Exception { MvcResult mvcResult; String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON) + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( @@ -797,10 +797,10 @@ void runWithReportTestElementsNotFoundAndNotConnected() throws Exception { Network network = EurostagTutorialExample1Factory.create(new NetworkFactoryImpl()); given(networkStoreService.getNetwork(NETWORK_UUID, PreloadingStrategy.COLLECTION)).willReturn(network); - given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_NAME), NETWORK_UUID, null)) + given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_UUID), NETWORK_UUID, null)) .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES); - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON) + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( @@ -900,7 +900,7 @@ void getNmKContingenciesResultNotFound() throws Exception { @Test void getZippedCsvResults() throws Exception { // running computation to create some results - MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_NAME + MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) .header(HEADER_USER_ID, "testUserId") .contentType(MediaType.APPLICATION_JSON)) diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java index c3e8e5fd..fe3bc5f1 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisProviderMock.java @@ -37,10 +37,10 @@ public class SecurityAnalysisProviderMock implements SecurityAnalysisProvider { private static final Logger LOGGER = LoggerFactory.getLogger(SecurityAnalysisProviderMock.class); - static final UUID CONTINGENCY_LIST_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791f"); //"list1"; - static final UUID CONTINGENCY_LIST2_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791g"); //"list2"; - static final UUID CONTINGENCY_LIST_ERROR_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791h"); //"listError"; - static final UUID CONTINGENCY_LIST_NAME_VARIANT = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791i"); //"listVariant"; + static final UUID CONTINGENCY_LIST_UUID = UUID.fromString("f7e8f79b-7626-4f46-939d-3bfdc895b0dd"); + static final UUID CONTINGENCY_LIST2_UUID = UUID.fromString("99fdbba0-0f30-4f24-b206-5481b00ad910"); + static final UUID CONTINGENCY_LIST_ERROR_UUID = UUID.fromString("d6e582ca-5084-4ad6-bf56-2ed3effdf9eb"); + static final UUID CONTINGENCY_LIST_UUID_VARIANT = UUID.fromString("98b6dcfc-0186-4aa6-a4e0-e4d04c4faab2"); static final List CONTINGENCIES = List.of( new ContingencyInfos(new Contingency("l1", new BranchContingency("l1")), Set.of("wrongId1, wrongId2"), Set.of()), diff --git a/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java b/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java index b40c39c1..327f0746 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/service/ActionsServiceTest.java @@ -55,10 +55,10 @@ class ActionsServiceTest { private static final String VARIANT_ID = "variant_id"; - private static final UUID LIST_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791j"); //"myList"; - private static final UUID LIST_NAME_VARIANT = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791k"); //"myListVariant"; + private static final UUID LIST_UUID = UUID.fromString("e6bc6e4b-bbf1-4342-a8ae-49b213f0c85a"); + private static final UUID LIST_UUID_VARIANT = UUID.fromString("81bb191f-b899-4999-91e3-2d158d208764"); - private static final UUID VERY_LARGE_LIST_NAME = UUID.fromString("6afd3d28-3f99-48d7-be9e-e97ffd0b791l"); //"veryLargelist"; + private static final UUID VERY_LARGE_LIST_UUID = UUID.fromString("4856bff4-9ebe-4ba2-b66d-0242f27fce7b"); public static final String WRONG_ID = "wrongID"; private static final ContingencyInfos CONTINGENCY = new ContingencyInfos(new Contingency("c1", new BranchContingency("b1")), Set.of(WRONG_ID), Set.of()); @@ -88,14 +88,14 @@ private String initMockWebServer(final MockWebServer server) throws IOException @Override public MockResponse dispatch(RecordedRequest request) { String requestPath = Objects.requireNonNull(request.getPath()); - if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&variantId=%s&ids=%s", NETWORK_UUID, VARIANT_ID, LIST_NAME))) { + if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&variantId=%s&ids=%s", NETWORK_UUID, VARIANT_ID, LIST_UUID))) { return new MockResponse(HttpStatus.OK.value(), Headers.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE), jsonVariantExpected); - } else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s", NETWORK_UUID, LIST_NAME))) { + } else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s", NETWORK_UUID, LIST_UUID))) { return new MockResponse(HttpStatus.OK.value(), Headers.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE), jsonExpected); - } else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&variantId=%s&ids=%s", NETWORK_UUID, VARIANT_ID, VERY_LARGE_LIST_NAME)) - || requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s", NETWORK_UUID, VERY_LARGE_LIST_NAME))) { + } else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&variantId=%s&ids=%s", NETWORK_UUID, VARIANT_ID, VERY_LARGE_LIST_UUID)) + || requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s", NETWORK_UUID, VERY_LARGE_LIST_UUID))) { return new MockResponse(HttpStatus.OK.value(), Headers.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE), veryLargeJsonExpected); - } else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s&ids=%s", NETWORK_UUID, LIST_NAME, LIST_NAME_VARIANT))) { + } else if (requestPath.equals(String.format("/v1/contingency-lists/contingency-infos/export?networkUuid=%s&ids=%s&ids=%s", NETWORK_UUID, LIST_UUID, LIST_UUID_VARIANT))) { return new MockResponse(HttpStatus.OK.value(), Headers.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE), jsonExpectedForList); } else { return new MockResponse.Builder().code(HttpStatus.NOT_FOUND.value()).body("Path not supported: " + request.getPath()).build(); @@ -117,26 +117,26 @@ private static List createVeryLargeList() { @Test void test() { - List list = actionsService.getContingencyList(List.of(LIST_NAME), UUID.fromString(NETWORK_UUID), null); + List list = actionsService.getContingencyList(List.of(LIST_UUID), UUID.fromString(NETWORK_UUID), null); list.forEach(contingencyInfos -> assertArrayEquals(List.of(WRONG_ID).toArray(new Object[0]), contingencyInfos.getNotFoundElements().toArray(new String[0]))); assertEquals(Stream.of(CONTINGENCY).map(ContingencyInfos::getContingency).toList(), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList())); - list = actionsService.getContingencyList(List.of(LIST_NAME), UUID.fromString(NETWORK_UUID), VARIANT_ID); + list = actionsService.getContingencyList(List.of(LIST_UUID), UUID.fromString(NETWORK_UUID), VARIANT_ID); assertEquals(Stream.of(CONTINGENCY_VARIANT).map(ContingencyInfos::getContingency).toList(), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList())); } @Test void testVeryLargeList() { // DataBufferLimitException should not be thrown with this message : "Exceeded limit on max bytes to buffer : DATA_BUFFER_LIMIT" - List list = actionsService.getContingencyList(List.of(VERY_LARGE_LIST_NAME), UUID.fromString(NETWORK_UUID), null); + List list = actionsService.getContingencyList(List.of(VERY_LARGE_LIST_UUID), UUID.fromString(NETWORK_UUID), null); list.forEach(contingencyInfos -> assertArrayEquals(List.of().toArray(new Object[0]), contingencyInfos.getNotFoundElements().toArray(new String[0]))); assertEquals(createVeryLargeList().stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList())); - list = actionsService.getContingencyList(List.of(VERY_LARGE_LIST_NAME), UUID.fromString(NETWORK_UUID), VARIANT_ID); + list = actionsService.getContingencyList(List.of(VERY_LARGE_LIST_UUID), UUID.fromString(NETWORK_UUID), VARIANT_ID); assertEquals(createVeryLargeList().stream().map(ContingencyInfos::getContingency).collect(Collectors.toList()), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList())); } @Test void testGetContingenciesByListOfIds() { - List list = actionsService.getContingencyList(List.of(LIST_NAME, LIST_NAME_VARIANT), UUID.fromString(NETWORK_UUID), null); + List list = actionsService.getContingencyList(List.of(LIST_UUID, LIST_UUID_VARIANT), UUID.fromString(NETWORK_UUID), null); assertEquals(Stream.of(CONTINGENCY, CONTINGENCY_VARIANT).map(ContingencyInfos::getContingency).toList(), list.stream().map(ContingencyInfos::getContingency).collect(Collectors.toList())); } } From f4d1817b361db502c7473daa4e6b16460437b953 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Mon, 16 Feb 2026 11:41:52 +0100 Subject: [PATCH 08/11] fix name --- .../SecurityAnalysisParametersController.java | 4 ++-- .../ContingencyListsInfos.java} | 6 ++--- .../dto/{ => parameters}/IdNameInfos.java | 2 +- .../LimitReductionsByVoltageLevel.java | 2 +- .../SecurityAnalysisParametersValues.java | 4 ++-- .../SecurityAnalysisParametersEntity.java | 22 +++++++++---------- .../server/service/LimitReductionService.java | 2 +- .../SecurityAnalysisParametersService.java | 12 ++++++---- .../SecurityAnalysisWorkerService.java | 2 +- ...urityAnalysisParametersControllerTest.java | 4 ++-- 10 files changed, 32 insertions(+), 28 deletions(-) rename src/main/java/org/gridsuite/securityanalysis/server/dto/{ParametersContingencyListDTO.java => parameters/ContingencyListsInfos.java} (77%) rename src/main/java/org/gridsuite/securityanalysis/server/dto/{ => parameters}/IdNameInfos.java (90%) rename src/main/java/org/gridsuite/securityanalysis/server/dto/{ => parameters}/LimitReductionsByVoltageLevel.java (94%) rename src/main/java/org/gridsuite/securityanalysis/server/dto/{ => parameters}/SecurityAnalysisParametersValues.java (93%) diff --git a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java index 4ea04323..da7c91df 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersController.java @@ -11,8 +11,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; -import org.gridsuite.securityanalysis.server.dto.LimitReductionsByVoltageLevel; -import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersValues; +import org.gridsuite.securityanalysis.server.dto.parameters.LimitReductionsByVoltageLevel; +import org.gridsuite.securityanalysis.server.dto.parameters.SecurityAnalysisParametersValues; import org.gridsuite.securityanalysis.server.service.SecurityAnalysisParametersService; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/ContingencyListsInfos.java similarity index 77% rename from src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java rename to src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/ContingencyListsInfos.java index de5cc980..ac6188c8 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/ParametersContingencyListDTO.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/ContingencyListsInfos.java @@ -4,7 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.gridsuite.securityanalysis.server.dto; +package org.gridsuite.securityanalysis.server.dto.parameters; import lombok.*; import java.util.List; @@ -17,8 +17,8 @@ @NoArgsConstructor @Getter @Setter -public class ParametersContingencyListDTO { - private List contingencies; +public class ContingencyListsInfos { + private List contingencyLists; private String description; private boolean activated; } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/IdNameInfos.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/IdNameInfos.java similarity index 90% rename from src/main/java/org/gridsuite/securityanalysis/server/dto/IdNameInfos.java rename to src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/IdNameInfos.java index 722ed24a..77fa5180 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/IdNameInfos.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/IdNameInfos.java @@ -4,7 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.gridsuite.securityanalysis.server.dto; +package org.gridsuite.securityanalysis.server.dto.parameters; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/LimitReductionsByVoltageLevel.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/LimitReductionsByVoltageLevel.java similarity index 94% rename from src/main/java/org/gridsuite/securityanalysis/server/dto/LimitReductionsByVoltageLevel.java rename to src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/LimitReductionsByVoltageLevel.java index b80ff880..abcca7ae 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/LimitReductionsByVoltageLevel.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/LimitReductionsByVoltageLevel.java @@ -4,7 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.gridsuite.securityanalysis.server.dto; +package org.gridsuite.securityanalysis.server.dto.parameters; import lombok.*; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/SecurityAnalysisParametersValues.java similarity index 93% rename from src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java rename to src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/SecurityAnalysisParametersValues.java index 20d48738..3105c361 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/dto/SecurityAnalysisParametersValues.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/parameters/SecurityAnalysisParametersValues.java @@ -4,7 +4,7 @@ License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.gridsuite.securityanalysis.server.dto; +package org.gridsuite.securityanalysis.server.dto.parameters; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; @@ -36,7 +36,7 @@ public class SecurityAnalysisParametersValues { private double flowProportionalThreshold; - private List contingencyLists; + private List contingencyListsInfos; private List limitReductions; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java index 82c46132..57e0c224 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/SecurityAnalysisParametersEntity.java @@ -8,9 +8,9 @@ import jakarta.persistence.*; import lombok.*; -import org.gridsuite.securityanalysis.server.dto.IdNameInfos; -import org.gridsuite.securityanalysis.server.dto.ParametersContingencyListDTO; -import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersValues; +import org.gridsuite.securityanalysis.server.dto.parameters.IdNameInfos; +import org.gridsuite.securityanalysis.server.dto.parameters.ContingencyListsInfos; +import org.gridsuite.securityanalysis.server.dto.parameters.SecurityAnalysisParametersValues; import org.springframework.lang.Nullable; import java.util.ArrayList; @@ -91,24 +91,24 @@ private void assignAttributes(SecurityAnalysisParametersValues securityAnalysisP this.highVoltageProportionalThreshold = securityAnalysisParametersValues.getHighVoltageProportionalThreshold(); this.lowVoltageAbsoluteThreshold = securityAnalysisParametersValues.getLowVoltageAbsoluteThreshold(); this.lowVoltageProportionalThreshold = securityAnalysisParametersValues.getLowVoltageProportionalThreshold(); - assignContingencyLists(securityAnalysisParametersValues.getContingencyLists()); + assignContingencyLists(securityAnalysisParametersValues.getContingencyListsInfos()); assignLimitReductions(securityAnalysisParametersValues.getLimitReductionsValues()); } - private void assignContingencyLists(List contingencyListsDTO) { - if (contingencyListsDTO == null) { + private void assignContingencyLists(List contingencyListsInfos) { + if (contingencyListsInfos == null) { return; } - List entities = contingencyListsDTO.stream() - .map(dto -> { - List contingencyListIds = dto.getContingencies().stream() + List entities = contingencyListsInfos.stream() + .map(listsInfos -> { + List contingencyListIds = listsInfos.getContingencyLists().stream() .map(IdNameInfos::getId) .toList(); ParametersContingencyListEntity entity = new ParametersContingencyListEntity( contingencyListIds, - dto.getDescription(), - dto.isActivated() + listsInfos.getDescription(), + listsInfos.isActivated() ); entity.setSecurityAnalysisParameters(this); return entity; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java index 2d8a2f5d..44eca241 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java @@ -10,7 +10,7 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.Range; -import org.gridsuite.securityanalysis.server.dto.LimitReductionsByVoltageLevel; +import org.gridsuite.securityanalysis.server.dto.parameters.LimitReductionsByVoltageLevel; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Service; diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java index 45b6570e..fca6c761 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java @@ -11,6 +11,10 @@ import org.gridsuite.computation.dto.ReportInfos; import lombok.NonNull; import org.gridsuite.securityanalysis.server.dto.*; +import org.gridsuite.securityanalysis.server.dto.parameters.ContingencyListsInfos; +import org.gridsuite.securityanalysis.server.dto.parameters.IdNameInfos; +import org.gridsuite.securityanalysis.server.dto.parameters.LimitReductionsByVoltageLevel; +import org.gridsuite.securityanalysis.server.dto.parameters.SecurityAnalysisParametersValues; import org.gridsuite.securityanalysis.server.entities.SecurityAnalysisParametersEntity; import org.gridsuite.securityanalysis.server.repositories.SecurityAnalysisParametersRepository; import org.springframework.beans.factory.annotation.Value; @@ -43,7 +47,7 @@ public class SecurityAnalysisParametersService { private static final double DEFAULT_HIGH_VOLTAGE_PROPORTIONAL_THRESHOLD = 0.01; // meaning 1.0 % private static final double DEFAULT_LOW_VOLTAGE_ABSOLUTE_THRESHOLD = 1.0; // 1.0 kV private static final double DEFAULT_HIGH_VOLTAGE_ABSOLUTE_THRESHOLD = 1.0; // 1.0 kV - private static final List DEFAULT_CONTINGENCY_LISTS = new ArrayList<>(); + private static final List DEFAULT_CONTINGENCY_LISTS_INFOS = new ArrayList<>(); public SecurityAnalysisParametersService(@NonNull SecurityAnalysisParametersRepository securityAnalysisParametersRepository, @NonNull LoadFlowService loadFlowService, @Value("${security-analysis.default-provider}") String defaultProvider, @NonNull LimitReductionService limitReductionService, @NonNull DirectoryService directoryService) { @@ -112,9 +116,9 @@ public SecurityAnalysisParametersValues toSecurityAnalysisParametersValues(Secur .highVoltageProportionalThreshold(entity.getHighVoltageProportionalThreshold()) .lowVoltageAbsoluteThreshold(entity.getLowVoltageAbsoluteThreshold()) .lowVoltageProportionalThreshold(entity.getLowVoltageProportionalThreshold()) - .contingencyLists(Optional.of( + .contingencyListsInfos(Optional.of( entity.getContingencyLists().stream() - .map(c -> new ParametersContingencyListDTO( + .map(c -> new ContingencyListsInfos( contingenciesIdsToDTOs(c.getContingencyListIds(), userId), c.getDescription(), c.isActivated())) @@ -162,7 +166,7 @@ public SecurityAnalysisParametersValues getDefaultSecurityAnalysisParametersValu .highVoltageAbsoluteThreshold(DEFAULT_HIGH_VOLTAGE_ABSOLUTE_THRESHOLD) .highVoltageProportionalThreshold(DEFAULT_HIGH_VOLTAGE_PROPORTIONAL_THRESHOLD) .flowProportionalThreshold(DEFAULT_FLOW_PROPORTIONAL_THRESHOLD) - .contingencyLists(DEFAULT_CONTINGENCY_LISTS) + .contingencyListsInfos(DEFAULT_CONTINGENCY_LISTS_INFOS) .limitReductions(limitReductionService.createDefaultLimitReductions()) .build(); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java index 503cf973..d5a91182 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisWorkerService.java @@ -29,7 +29,7 @@ import org.gridsuite.computation.service.*; import org.gridsuite.securityanalysis.server.PropertyServerNameProvider; import org.gridsuite.securityanalysis.server.dto.ContingencyInfos; -import org.gridsuite.securityanalysis.server.dto.LimitReductionsByVoltageLevel; +import org.gridsuite.securityanalysis.server.dto.parameters.LimitReductionsByVoltageLevel; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersDTO; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus; import org.gridsuite.securityanalysis.server.util.SecurityAnalysisRunnerSupplier; diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java index e6a429d0..519c7533 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java @@ -9,8 +9,8 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.gridsuite.computation.error.ComputationException; -import org.gridsuite.securityanalysis.server.dto.LimitReductionsByVoltageLevel; -import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersValues; +import org.gridsuite.securityanalysis.server.dto.parameters.LimitReductionsByVoltageLevel; +import org.gridsuite.securityanalysis.server.dto.parameters.SecurityAnalysisParametersValues; import org.gridsuite.securityanalysis.server.entities.SecurityAnalysisParametersEntity; import org.gridsuite.securityanalysis.server.repositories.SecurityAnalysisParametersRepository; import org.gridsuite.securityanalysis.server.service.LimitReductionService; From 764b192ef84962415f0fb9398e45d2292546da7a Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Mon, 16 Feb 2026 14:16:34 +0100 Subject: [PATCH 09/11] fix changelog --- .../changesets/changelog_20260209T074419Z.xml | 33 ------------------- .../changesets/changelog_20260216T131402Z.xml | 33 +++++++++++++++++++ .../db/changelog/db.changelog-master.yaml | 4 +-- 3 files changed, 35 insertions(+), 35 deletions(-) delete mode 100644 src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml create mode 100644 src/main/resources/db/changelog/changesets/changelog_20260216T131402Z.xml diff --git a/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml b/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml deleted file mode 100644 index b78fb8f7..00000000 --- a/src/main/resources/db/changelog/changesets/changelog_20260209T074419Z.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/db/changelog/changesets/changelog_20260216T131402Z.xml b/src/main/resources/db/changelog/changesets/changelog_20260216T131402Z.xml new file mode 100644 index 00000000..307fd292 --- /dev/null +++ b/src/main/resources/db/changelog/changesets/changelog_20260216T131402Z.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 7442be2f..ebff5a4e 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -55,5 +55,5 @@ databaseChangeLog: file: changesets/changelog_20260116T110615Z.xml relativeToChangelogFile: true - include: - file: changesets/changelog_20260209T074419Z.xml - relativeToChangelogFile: true + file: changesets/changelog_20260216T131402Z.xml + relativeToChangelogFile: true \ No newline at end of file From 499ff68d3dc09908add3db7e9d2a38c0260afa63 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Wed, 18 Feb 2026 15:21:22 +0100 Subject: [PATCH 10/11] address review comments & fix existing tests --- .../server/dto/ElementAttributes.java | 28 ++++ .../ParametersContingencyListEntity.java | 2 +- .../server/service/DirectoryService.java | 17 ++- ...02Z.xml => changelog_20260218T115944Z.xml} | 14 +- .../db/changelog/db.changelog-master.yaml | 6 +- .../SecurityAnalysisControllerTest.java | 127 ++++-------------- ...urityAnalysisParametersControllerTest.java | 90 ++++++++++++- 7 files changed, 156 insertions(+), 128 deletions(-) create mode 100644 src/main/java/org/gridsuite/securityanalysis/server/dto/ElementAttributes.java rename src/main/resources/db/changelog/changesets/{changelog_20260216T131402Z.xml => changelog_20260218T115944Z.xml} (81%) diff --git a/src/main/java/org/gridsuite/securityanalysis/server/dto/ElementAttributes.java b/src/main/java/org/gridsuite/securityanalysis/server/dto/ElementAttributes.java new file mode 100644 index 00000000..580a0107 --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/dto/ElementAttributes.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +/** + * partial type from ElementAttributes (Directory-server) + * @author Caroline Jeandat {@literal } + */ +@AllArgsConstructor +@NoArgsConstructor +public class ElementAttributes { + @Getter + private UUID elementUuid; + @Setter + @Getter + private String elementName; +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java index a8c8816b..fb214179 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/entities/ParametersContingencyListEntity.java @@ -45,7 +45,7 @@ public class ParametersContingencyListEntity { private boolean activated; @ManyToOne - @JoinColumn(name = "security_analysis_parameters_id") + @JoinColumn(name = "security_analysis_parameters_id", foreignKey = @ForeignKey(name = "security_analysis_parameters_id_fk")) private SecurityAnalysisParametersEntity securityAnalysisParameters; public ParametersContingencyListEntity(List contingencyListIds, String description, boolean activated) { diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java index cdba6e1a..ab3a438d 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/DirectoryService.java @@ -6,6 +6,7 @@ */ package org.gridsuite.securityanalysis.server.service; +import org.gridsuite.securityanalysis.server.dto.ElementAttributes; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.*; @@ -47,6 +48,7 @@ public Map getElementNames(List elementUuids, String userId) URI path = UriComponentsBuilder .fromPath(DELIMITER + DIRECTORY_API_VERSION + "/elements") .queryParam("ids", elementUuids) + .queryParam("strictMode", "false") // to ignore non existing elements error .build() .toUri(); @@ -55,21 +57,18 @@ public Map getElementNames(List elementUuids, String userId) headers.setContentType(MediaType.APPLICATION_JSON); try { - ResponseEntity>> response = + List elementAttributes = restTemplate.exchange( baseUri + path, HttpMethod.GET, new HttpEntity<>(headers), - new ParameterizedTypeReference<>() { } - ); + new ParameterizedTypeReference>() { } + ).getBody(); - List> responseBody = response.getBody(); - return responseBody != null ? responseBody.stream().collect(Collectors.toMap( - e -> UUID.fromString((String) e.get("elementUuid")), - e -> (String) e.get("elementName") - )) : Map.of(); + return elementAttributes == null ? Map.of() + : elementAttributes.stream().collect(Collectors.toMap(ElementAttributes::getElementUuid, ElementAttributes::getElementName)); - } catch (HttpClientErrorException.NotFound e) { + } catch (HttpClientErrorException e) { return Map.of(); } } diff --git a/src/main/resources/db/changelog/changesets/changelog_20260216T131402Z.xml b/src/main/resources/db/changelog/changesets/changelog_20260218T115944Z.xml similarity index 81% rename from src/main/resources/db/changelog/changesets/changelog_20260216T131402Z.xml rename to src/main/resources/db/changelog/changesets/changelog_20260218T115944Z.xml index 307fd292..28a28cd9 100644 --- a/src/main/resources/db/changelog/changesets/changelog_20260216T131402Z.xml +++ b/src/main/resources/db/changelog/changesets/changelog_20260218T115944Z.xml @@ -1,6 +1,6 @@ - + @@ -11,7 +11,7 @@ - + @@ -19,15 +19,15 @@ - + - - - - + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index c96042a8..6d91d0ba 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -54,9 +54,9 @@ databaseChangeLog: - include: file: changesets/changelog_20260116T110615Z.xml relativeToChangelogFile: true - - include: - file: changesets/changelog_20260216T131402Z.xml - relativeToChangelogFile: true - include: file: changesets/changelog_20260212T120615Z.xml relativeToChangelogFile: true + - include: + file: changesets/changelog_20260218T115944Z.xml + relativeToChangelogFile: true \ No newline at end of file diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java index ca5c2fb7..3bead74f 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java @@ -81,7 +81,6 @@ import static org.gridsuite.securityanalysis.server.service.SecurityAnalysisService.COMPUTATION_TYPE; import static org.gridsuite.securityanalysis.server.util.CsvExportUtils.csvRowsToZippedCsv; import static org.gridsuite.securityanalysis.server.util.DatabaseQueryUtils.assertRequestsCount; -import static org.gridsuite.securityanalysis.server.util.TestUtils.assertLogMessage; import static org.gridsuite.securityanalysis.server.util.TestUtils.readLinesFromFilePath; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -109,11 +108,10 @@ class SecurityAnalysisControllerTest { private static final UUID REPORT_UUID = UUID.fromString("0c4de370-3e6a-4d72-b292-d355a97e0d53"); private static final UUID OTHER_RESULT_UUID = UUID.fromString("0c8de370-3e6c-4d72-b292-d355a97e0d5a"); private static final UUID LIST_FILTER_ID = UUID.fromString("762b72a8-8c0f-11ed-a1eb-0242ac120003"); + private static final String USER_ID = "testUserId"; private static final int TIMEOUT = 1000; - private static final String ERROR_MESSAGE = "Error message test"; - @Autowired private OutputDestination output; @@ -239,9 +237,9 @@ void tearDown() throws Exception { } private void simpleRunRequest(SecurityAnalysisParametersInfos lfParams) throws Exception { - MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID_VARIANT + "&variantId=" + VARIANT_3_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) + MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&variantId=" + VARIANT_3_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) .contentType(MediaType.APPLICATION_JSON) - .header(HEADER_USER_ID, "testUserId") + .header(HEADER_USER_ID, USER_ID) .content(mapper.writeValueAsString(lfParams))) .andExpectAll( status().isOk(), @@ -273,8 +271,8 @@ void runTest() throws Exception { String resultAsString; // run with specific variant - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID_VARIANT + "&variantId=" + VARIANT_3_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&variantId=" + VARIANT_3_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), @@ -286,8 +284,8 @@ void runTest() throws Exception { assertThat(RESULT_VARIANT, new MatcherJson<>(mapper, securityAnalysisResult)); // run with implicit initial variant - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), @@ -305,9 +303,8 @@ void runAndSaveTest() throws Exception { String resultAsString; SQLStatementCountValidator.reset(); - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID - + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), @@ -371,9 +368,8 @@ void testDeterministicResults() throws Exception { MvcResult mvcResult; String resultAsString; SQLStatementCountValidator.reset(); - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID - + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( content().contentType(MediaType.APPLICATION_JSON), @@ -587,30 +583,13 @@ private void verifyNmkContingrnciesResultLocationIds(List Assertions.assertThat(locationIds).hasSameElementsAs(Arrays.asList(null, "vl1 (VLGEN_0, VLLOAD_0)", "vl7")); } - @Test - void runWithTwoLists() throws Exception { - MvcResult mvcResult; - String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + - "&contingencyListName=" + CONTINGENCY_LIST2_UUID + "&variantId=" + VARIANT_1_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .contentType(MediaType.APPLICATION_JSON) - .header(HEADER_USER_ID, "testUserId")) - .andExpectAll( - status().isOk(), - content().contentType(MediaType.APPLICATION_JSON) - ).andReturn(); - resultAsString = mvcResult.getResponse().getContentAsString(); - SecurityAnalysisResult securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class); - assertThat(RESULT, new MatcherJson<>(mapper, securityAnalysisResult)); - } - @Test void deleteResultsTest() throws Exception { MvcResult mvcResult; String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), @@ -654,9 +633,8 @@ void testStatus() throws Exception { assertEquals(SecurityAnalysisStatus.NOT_DONE, securityAnalysisStatus); // running computation to create result - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID - + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), @@ -701,9 +679,8 @@ void stopTest() throws Exception { MvcResult mvcResult; String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_STOP_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID - + "&receiver=me&variantId=" + VARIANT_TO_STOP_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_STOP_UUID + "/run-and-save?reportType=SecurityAnalysis&receiver=me&variantId=" + VARIANT_TO_STOP_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), @@ -722,7 +699,7 @@ void stopTest() throws Exception { countDownLatch.await(); mockMvc.perform(put("/" + VERSION + "/results/" + RESULT_UUID + "/stop" + "?receiver=me") - .header(HEADER_USER_ID, "testUserId")) + .header(HEADER_USER_ID, USER_ID)) .andExpect(status().isOk()); Message message = output.receive(TIMEOUT * 3, "sa.stopped"); @@ -735,7 +712,7 @@ void stopTest() throws Exception { void testStopAndFail() throws Exception { UUID randomUuid = UUID.randomUUID(); mockMvc.perform(put("/" + VERSION + "/results/" + randomUuid + "/stop" + "?receiver=me") - .header(HEADER_USER_ID, "testUserId")) + .header(HEADER_USER_ID, USER_ID)) .andExpect(status().isOk()); Message message = output.receive(TIMEOUT * 3, "sa.cancelfailed"); @@ -744,41 +721,13 @@ void testStopAndFail() throws Exception { assertEquals(getCancelFailedMessage(COMPUTATION_TYPE), message.getHeaders().get("message")); } - @Test - void runTestWithError() throws Exception { - MvcResult mvcResult; - String resultAsString; - - given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_ERROR_UUID), NETWORK_UUID, VARIANT_1_ID)) - .willThrow(new RuntimeException(ERROR_MESSAGE)); - - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_ERROR_UUID - + "&receiver=me&variantId=" + VARIANT_1_ID + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") - .contentType(MediaType.APPLICATION_JSON)) - .andExpectAll( - status().isOk(), - content().contentType(MediaType.APPLICATION_JSON) - ).andReturn(); - - resultAsString = mvcResult.getResponse().getContentAsString(); - UUID resultUuid = mapper.readValue(resultAsString, UUID.class); - assertEquals(RESULT_UUID, resultUuid); - - // No result message - assertNull(output.receive(TIMEOUT, "sa.result")); - - // No result - assertResultNotFound(RESULT_UUID); - } - @Test void runWithReportTest() throws Exception { MvcResult mvcResult; String resultAsString; - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON) - .header(HEADER_USER_ID, "testUserId") + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), @@ -790,35 +739,6 @@ void runWithReportTest() throws Exception { assertThat(RESULT, new MatcherJson<>(mapper, securityAnalysisResult)); } - @Test - void runWithReportTestElementsNotFoundAndNotConnected() throws Exception { - MvcResult mvcResult; - String resultAsString; - - Network network = EurostagTutorialExample1Factory.create(new NetworkFactoryImpl()); - given(networkStoreService.getNetwork(NETWORK_UUID, PreloadingStrategy.COLLECTION)).willReturn(network); - given(actionsService.getContingencyList(List.of(CONTINGENCY_LIST_UUID), NETWORK_UUID, null)) - .willReturn(SecurityAnalysisProviderMock.CONTINGENCIES); - - mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID + "&provider=testProvider" + "&reportUuid=" + REPORT_UUID + "&reporterId=" + UUID.randomUUID() + "&loadFlowParametersUuid=" + UUID.randomUUID()).contentType(MediaType.APPLICATION_JSON) - .header(HEADER_USER_ID, "testUserId") - .contentType(MediaType.APPLICATION_JSON)) - .andExpectAll( - status().isOk(), - content().contentType(MediaType.APPLICATION_JSON)) - .andReturn(); - - resultAsString = mvcResult.getResponse().getContentAsString(); - SecurityAnalysisResult securityAnalysisResult = mapper.readValue(resultAsString, SecurityAnalysisResult.class); - assertThat(RESULT, new MatcherJson<>(mapper, securityAnalysisResult)); - - assertLogMessage("Equipments not found", "security.analysis.server.notFoundEquipments", reportService); - assertLogMessage("Cannot find the following equipments wrongId1, wrongId2 in contingency l1", "security.analysis.server.contingencyEquipmentNotFound", reportService); - - assertLogMessage("Equipments not connected", "security.analysis.server.notConnectedEquipments", reportService); - assertLogMessage("The following equipments notConnectedId1 in contingency l4 are not connected", "security.analysis.server.contingencyEquipmentNotConnected", reportService); - } - @Test void getProvidersTest() throws Exception { MvcResult mvcResult; @@ -900,9 +820,8 @@ void getNmKContingenciesResultNotFound() throws Exception { @Test void getZippedCsvResults() throws Exception { // running computation to create some results - MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&contingencyListName=" + CONTINGENCY_LIST_UUID - + "&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) - .header(HEADER_USER_ID, "testUserId") + MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&receiver=me&variantId=" + VARIANT_2_ID + "&provider=OpenLoadFlow" + "&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isOk(), diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java index 519c7533..909444c1 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java @@ -8,31 +8,42 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.vladmihalcea.sql.SQLStatementCountValidator; import org.gridsuite.computation.error.ComputationException; +import org.gridsuite.securityanalysis.server.dto.parameters.ContingencyListsInfos; +import org.gridsuite.securityanalysis.server.dto.parameters.IdNameInfos; import org.gridsuite.securityanalysis.server.dto.parameters.LimitReductionsByVoltageLevel; import org.gridsuite.securityanalysis.server.dto.parameters.SecurityAnalysisParametersValues; import org.gridsuite.securityanalysis.server.entities.SecurityAnalysisParametersEntity; import org.gridsuite.securityanalysis.server.repositories.SecurityAnalysisParametersRepository; +import org.gridsuite.securityanalysis.server.service.DirectoryService; import org.gridsuite.securityanalysis.server.service.LimitReductionService; import org.gridsuite.securityanalysis.server.service.SecurityAnalysisParametersService; import org.gridsuite.securityanalysis.server.util.ContextConfigurationWithTestChannel; import org.gridsuite.securityanalysis.server.util.MatcherJson; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import java.util.List; +import java.util.Map; import java.util.UUID; import static com.powsybl.network.store.model.NetworkStoreApi.VERSION; import static org.gridsuite.computation.error.ComputationBusinessErrorCode.PARAMETERS_NOT_FOUND; +import static org.gridsuite.computation.service.NotificationService.HEADER_USER_ID; +import static org.gridsuite.securityanalysis.server.util.DatabaseQueryUtils.assertRequestsCount; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -40,6 +51,7 @@ /** * @author Abdelsalem Hedhili */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) @AutoConfigureMockMvc @SpringBootTest @ContextConfigurationWithTestChannel @@ -63,6 +75,35 @@ class SecurityAnalysisParametersControllerTest { @Autowired private LimitReductionService limitReductionService; + @MockitoBean + private DirectoryService directoryService; + + private static final String USER_ID = "userId"; + private static final UUID CONTINGENCY_LIST_ID = UUID.fromString("3f7c9e2a-8b41-4d6a-a1f3-9c5b72e8d4af"); + private static final String CONTINGENCY_LIST_NAME = "contingencyList"; + private static final UUID DEACTIVATED_CONTINGENCY_LIST_ID = UUID.fromString("b8a4f2c1-6d3e-4a9b-92f7-1e5c8d7a3b60"); + private static final String DEACTIVATED_CONTINGENCY_LIST_NAME = "deactivatedContingencyList"; + + private List deactivatedContingencyListsInfos; + private List contingencyListsInfos; + + @BeforeEach + void setUp() { + contingencyListsInfos = List.of(new ContingencyListsInfos( + List.of(new IdNameInfos(CONTINGENCY_LIST_ID, CONTINGENCY_LIST_NAME)), + "activated contingency lists", + true)); + when(directoryService.getElementNames(List.of(CONTINGENCY_LIST_ID), USER_ID)) + .thenReturn(Map.of(CONTINGENCY_LIST_ID, CONTINGENCY_LIST_NAME)); + + deactivatedContingencyListsInfos = List.of(new ContingencyListsInfos( + List.of(new IdNameInfos(DEACTIVATED_CONTINGENCY_LIST_ID, DEACTIVATED_CONTINGENCY_LIST_NAME)), + "deactivated contingency lists", + false)); + when(directoryService.getElementNames(List.of(DEACTIVATED_CONTINGENCY_LIST_ID), USER_ID)) + .thenReturn(Map.of(DEACTIVATED_CONTINGENCY_LIST_ID, DEACTIVATED_CONTINGENCY_LIST_NAME)); + } + @Test void limitReductionConfigTest() { List limitReductions = limitReductionService.createDefaultLimitReductions(); @@ -138,8 +179,41 @@ void securityAnalysisParametersCreateAndGetTest() throws Exception { .limitReductions(limitReductionService.createLimitReductions(limitReductions)) .build()); + // Get with deactivated contingency lists + SQLStatementCountValidator.reset(); + testParametersCreateAndGetTest(builder.contingencyListsInfos(deactivatedContingencyListsInfos).build()); + /* + insert + security_analysis_parameters + parameters_contingency_lists + limit_reduction_entity + limit_reduction_entity_reductions + parameters_contingency_lists_contingency_list + update + parameters_contingency_lists + limit_reduction_entity + */ + assertRequestsCount(5, 5, 2, 0); + + // Get with contingency lists + SQLStatementCountValidator.reset(); + testParametersCreateAndGetTest(builder.contingencyListsInfos(contingencyListsInfos).build()); + /* + insert + security_analysis_parameters + parameters_contingency_lists + limit_reduction_entity + limit_reduction_entity_reductions + parameters_contingency_lists_contingency_list + update + parameters_contingency_lists + limit_reduction_entity + */ + assertRequestsCount(5, 5, 2, 0); + // Get not existing parameters and expect 404 - mockMvc.perform(get("/" + VERSION + "/parameters/" + UUID.randomUUID())) + mockMvc.perform(get("/" + VERSION + "/parameters/" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID)) .andExpect(status().isNotFound()); } @@ -149,6 +223,7 @@ private void testParametersCreateAndGetTest(SecurityAnalysisParametersValues par private void testParametersCreateAndGetTest(SecurityAnalysisParametersValues parametersToCreate, SecurityAnalysisParametersValues parametersExpected) throws Exception { MvcResult mvcResult = mockMvc.perform(post("/" + VERSION + "/parameters") + .header(HEADER_USER_ID, USER_ID) .content(objectMapper.writeValueAsString(parametersToCreate)) .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( @@ -162,7 +237,8 @@ private void testParametersCreateAndGetTest(SecurityAnalysisParametersValues par assertSecurityAnalysisParametersEntityAreEquals(createdParametersUuid, 10, 11, 12, 13, 14); // Get the created parameters - mvcResult = mockMvc.perform(get("/" + VERSION + "/parameters/" + createdParametersUuid)) + mvcResult = mockMvc.perform(get("/" + VERSION + "/parameters/" + createdParametersUuid) + .header(HEADER_USER_ID, USER_ID)) .andExpectAll( status().isOk(), content().contentType(MediaType.APPLICATION_JSON) @@ -211,6 +287,7 @@ void securityAnalysisParametersUpdateTest() throws Exception { .highVoltageAbsoluteThreshold(12) .highVoltageProportionalThreshold(13) .flowProportionalThreshold(14) + .contingencyListsInfos(contingencyListsInfos) .limitReductions(limitReductionService.createLimitReductions(limitReductions)) .build(); @@ -270,6 +347,7 @@ void testDuplicateParameters() throws Exception { .highVoltageAbsoluteThreshold(12) .highVoltageProportionalThreshold(13) .flowProportionalThreshold(14) + .contingencyListsInfos(contingencyListsInfos) .limitReductions(limitReductionService.createLimitReductions(limitReductions)) .build(); @@ -288,7 +366,8 @@ void testDuplicateParameters() throws Exception { assertSecurityAnalysisParametersEntityAreEquals(createdParametersUuid, 10, 11, 12, 13, 14); //duplicate - mvcResult = mockMvc.perform(post("/" + VERSION + "/parameters").queryParam("duplicateFrom", createdParametersUuid.toString())) + mvcResult = mockMvc.perform(post("/" + VERSION + "/parameters").queryParam("duplicateFrom", createdParametersUuid.toString()) + .header(HEADER_USER_ID, USER_ID)) .andExpectAll( status().isOk(), content().contentType(MediaType.APPLICATION_JSON) @@ -300,7 +379,9 @@ void testDuplicateParameters() throws Exception { assertSecurityAnalysisParametersEntityAreEquals(duplicatedParametersUuid, 10, 11, 12, 13, 14); //duplicate not existing parameters and expect a 404 - mockMvc.perform(post("/" + VERSION + "/parameters").queryParam("duplicateFrom", UUID.randomUUID().toString())) + mockMvc.perform(post("/" + VERSION + "/parameters") + .header(HEADER_USER_ID, USER_ID) + .queryParam("duplicateFrom", UUID.randomUUID().toString())) .andExpectAll( status().isNotFound() ).andReturn(); @@ -319,6 +400,7 @@ void testRemoveParameters() throws Exception { .highVoltageAbsoluteThreshold(12) .highVoltageProportionalThreshold(13) .flowProportionalThreshold(14) + .contingencyListsInfos(contingencyListsInfos) .limitReductions(limitReductionService.createLimitReductions(limitReductions)) .build(); From 2db546393ac4e5a96400aaba4e738fd19ebd3ce4 Mon Sep 17 00:00:00 2001 From: Caroline Jeandat Date: Wed, 18 Feb 2026 18:25:32 +0100 Subject: [PATCH 11/11] add tests --- .../server/service/DirectoryServiceTest.java | 98 +++++++++++++++++++ ...SecurityAnalysisParametersServiceTest.java | 53 ++++++++++ 2 files changed, 151 insertions(+) create mode 100644 src/test/java/org/gridsuite/securityanalysis/server/service/DirectoryServiceTest.java create mode 100644 src/test/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersServiceTest.java diff --git a/src/test/java/org/gridsuite/securityanalysis/server/service/DirectoryServiceTest.java b/src/test/java/org/gridsuite/securityanalysis/server/service/DirectoryServiceTest.java new file mode 100644 index 00000000..b39f01b2 --- /dev/null +++ b/src/test/java/org/gridsuite/securityanalysis/server/service/DirectoryServiceTest.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import org.gridsuite.securityanalysis.server.dto.ElementAttributes; +import org.gridsuite.securityanalysis.server.util.ContextConfigurationWithTestChannel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.util.ReflectionTestUtils; +import static org.gridsuite.computation.service.NotificationService.HEADER_USER_ID; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Caroline Jeandat {@literal } + */ +@AutoConfigureMockMvc +@SpringBootTest +@ContextConfigurationWithTestChannel +class DirectoryServiceTest { + + private WireMockServer wireMockServer; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private DirectoryService directoryService; + + private static final String USER_ID = "userId"; + private static final UUID CONTINGENCY_LIST_ID_1 = UUID.fromString("3f7c9e2a-8b41-4d6a-a1f3-9c5b72e8d4af"); + private static final String CONTINGENCY_LIST_NAME_1 = "contingencyList1"; + private static final UUID CONTINGENCY_LIST_ID_2 = UUID.fromString("b8a4f2c1-6d3e-4a9b-92f7-1e5c8d7a3b60"); + private static final String CONTINGENCY_LIST_NAME_2 = "contingencyList2"; + + @BeforeEach + void setUp() { + wireMockServer = new WireMockServer(wireMockConfig().dynamicPort()); + wireMockServer.start(); + ReflectionTestUtils.setField(directoryService, "baseUri", wireMockServer.baseUrl()); + } + + @AfterEach + void tearDown() { + wireMockServer.stop(); + } + + @Test + void getElementNamesWithNullElementUuidsTest() { + assertThrows(NullPointerException.class, + () -> directoryService.getElementNames(null, USER_ID)); + } + + @Test + void getElementNamesWithEmptyElementUuidsTest() { + assertEquals(Map.of(), directoryService.getElementNames(List.of(), USER_ID)); + } + + @Test + void getElementNamesTest() throws JsonProcessingException { + List elementAttributes = List.of( + new ElementAttributes(CONTINGENCY_LIST_ID_1, CONTINGENCY_LIST_NAME_1), + new ElementAttributes(CONTINGENCY_LIST_ID_2, CONTINGENCY_LIST_NAME_2) + ); + wireMockServer.stubFor(WireMock.get(WireMock.urlPathEqualTo("/v1/elements")) + .withQueryParam("ids", WireMock.equalTo(CONTINGENCY_LIST_ID_1.toString())) + .withQueryParam("ids", WireMock.equalTo(CONTINGENCY_LIST_ID_2.toString())) + .withQueryParam("strictMode", WireMock.equalTo("false")) + .withHeader(HEADER_USER_ID, WireMock.equalTo(USER_ID)) + .willReturn(WireMock.ok().withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).withBody(objectMapper.writeValueAsString(elementAttributes)))); + + Map elementNames = Map.of( + CONTINGENCY_LIST_ID_1, CONTINGENCY_LIST_NAME_1, + CONTINGENCY_LIST_ID_2, CONTINGENCY_LIST_NAME_2 + ); + assertEquals(elementNames, directoryService.getElementNames(List.of(CONTINGENCY_LIST_ID_1, CONTINGENCY_LIST_ID_2), USER_ID)); + } +} diff --git a/src/test/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersServiceTest.java b/src/test/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersServiceTest.java new file mode 100644 index 00000000..a9032e21 --- /dev/null +++ b/src/test/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersServiceTest.java @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server.service; + +import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersDTO; +import org.gridsuite.securityanalysis.server.entities.ParametersContingencyListEntity; +import org.gridsuite.securityanalysis.server.entities.SecurityAnalysisParametersEntity; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Caroline Jeandat {@literal } + */ +@SpringBootTest +class SecurityAnalysisParametersServiceTest { + + @Autowired + SecurityAnalysisParametersService securityAnalysisParametersService; + + private static final UUID CONTINGENCY_LIST_ID = UUID.fromString("3f7c9e2a-8b41-4d6a-a1f3-9c5b72e8d4af"); + private static final UUID DEACTIVATED_CONTINGENCY_LIST_ID = UUID.fromString("b8a4f2c1-6d3e-4a9b-92f7-1e5c8d7a3b60"); + + @Test + void toSecurityAnalysisParametersWithContingencyListsTest() { + // result securityAnalysisParameters should only contain the "activated" contingencyLists + SecurityAnalysisParametersEntity entity = SecurityAnalysisParametersEntity.builder() + .contingencyLists(List.of( + new ParametersContingencyListEntity(List.of(CONTINGENCY_LIST_ID), "", true), + new ParametersContingencyListEntity(List.of(DEACTIVATED_CONTINGENCY_LIST_ID), "", false) + )) + .limitReductions(List.of()) + .build(); + SecurityAnalysisParametersDTO parameters = securityAnalysisParametersService.toSecurityAnalysisParameters(entity); + assertEquals(List.of(CONTINGENCY_LIST_ID), parameters.contingencyListUuids()); + + SecurityAnalysisParametersEntity entityWithoutContingencyLists = SecurityAnalysisParametersEntity.builder() + .contingencyLists(null) + .limitReductions(List.of()) + .build(); + SecurityAnalysisParametersDTO parametersWithoutContingencyLists = securityAnalysisParametersService.toSecurityAnalysisParameters(entityWithoutContingencyLists); + assertEquals(List.of(), parametersWithoutContingencyLists.contingencyListUuids()); + } +}