From 5fb0eeb6313369090a4f346ee71baf810d557ad6 Mon Sep 17 00:00:00 2001 From: Thang PHAM Date: Thu, 8 Jan 2026 19:54:29 +0100 Subject: [PATCH 1/6] DMC - Functional implementation Signed-off-by: Thang PHAM --- .../study/server/StudyConstants.java | 1 + .../server/controller/StudyController.java | 70 +++ .../study/server/dto/ComputationType.java | 40 +- .../study/server/dto/DeleteNodeInfos.java | 6 + .../study/server/dto/InvalidateNodeInfos.java | 10 + .../study/server/dto/RootNetworkNodeInfo.java | 3 + .../study/server/dto/UserProfileInfos.java | 3 + .../DynamicMarginCalculationStatus.java | 18 + ...ynamicSecurityAnalysisParametersInfos.java | 40 -- .../dto/NetworkModificationNode.java | 3 + .../entities/RootNetworkNodeInfoEntity.java | 4 + .../notification/NotificationService.java | 17 + .../study/server/repository/StudyEntity.java | 3 + .../RootNetworkNodeInfoRepository.java | 2 + .../study/server/service/ConsumerService.java | 57 +- .../service/RootNetworkNodeInfoService.java | 215 ++----- .../study/server/service/StudyService.java | 193 +++++- .../server/service/SupervisionService.java | 17 + .../DynamicMarginCalculationClient.java | 276 +++++++++ .../DynamicMarginCalculationService.java | 133 +++++ src/main/resources/application-local.yml | 3 + src/main/resources/config/application.yaml | 19 + .../changesets/changelog_20260106T162321Z.xml | 13 + .../db/changelog/db.changelog-master.yaml | 3 + .../study/server/LoadFLowUnitTest.java | 4 +- .../gridsuite/study/server/LoadFlowTest.java | 70 +-- .../study/server/NetworkModificationTest.java | 225 ++++--- .../server/NetworkModificationTreeTest.java | 344 ++++------- .../server/NetworkModificationUnitTest.java | 39 +- ...ontrollerDynamicMarginCalculationTest.java | 565 ++++++++++++++++++ ...ControllerDynamicSecurityAnalysisTest.java | 15 +- .../StudyControllerDynamicSimulationTest.java | 6 +- .../study/server/VoltageInitTest.java | 11 +- .../server/rootnetworks/RootNetworkTest.java | 6 + .../StudyServiceCreateGridLayoutTest.java | 2 +- .../DynamicMarginCalculationClientTest.java | 512 ++++++++++++++++ .../DynamicSecurityAnalysisClientTest.java | 32 +- .../DynamicMarginCalculationServiceTest.java | 224 +++++++ .../server/studycontroller/StudyTest.java | 115 +--- .../study/server/utils/TestUtils.java | 26 +- .../server/utils/assertions/Assertions.java | 7 - 41 files changed, 2574 insertions(+), 778 deletions(-) create mode 100644 src/main/java/org/gridsuite/study/server/dto/dynamicmargincalculation/DynamicMarginCalculationStatus.java delete mode 100644 src/main/java/org/gridsuite/study/server/dto/dynamicsecurityanalysis/DynamicSecurityAnalysisParametersInfos.java create mode 100644 src/main/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClient.java create mode 100644 src/main/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationService.java create mode 100644 src/main/resources/db/changelog/changesets/changelog_20260106T162321Z.xml create mode 100644 src/test/java/org/gridsuite/study/server/StudyControllerDynamicMarginCalculationTest.java create mode 100644 src/test/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClientTest.java create mode 100644 src/test/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationServiceTest.java diff --git a/src/main/java/org/gridsuite/study/server/StudyConstants.java b/src/main/java/org/gridsuite/study/server/StudyConstants.java index 24bcf82593..a7133162ac 100644 --- a/src/main/java/org/gridsuite/study/server/StudyConstants.java +++ b/src/main/java/org/gridsuite/study/server/StudyConstants.java @@ -26,6 +26,7 @@ private StudyConstants() { public static final String SECURITY_ANALYSIS_API_VERSION = "v1"; public static final String DYNAMIC_SIMULATION_API_VERSION = "v1"; public static final String DYNAMIC_SECURITY_ANALYSIS_API_VERSION = "v1"; + public static final String DYNAMIC_MARGIN_CALCULATION_API_VERSION = "v1"; public static final String SENSITIVITY_ANALYSIS_API_VERSION = "v1"; public static final String ACTIONS_API_VERSION = "v1"; public static final String NETWORK_MAP_API_VERSION = "v1"; diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index 6084fb834d..af7fd83e9a 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -6,6 +6,7 @@ */ package org.gridsuite.study.server.controller; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.powsybl.iidm.network.ThreeSides; import com.powsybl.timeseries.DoubleTimeSeries; @@ -19,6 +20,7 @@ import org.gridsuite.filter.utils.EquipmentType; import org.gridsuite.study.server.StudyApi; import org.gridsuite.study.server.StudyConstants.ModificationsActionType; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata; import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.dto.*; @@ -1159,6 +1161,23 @@ public ResponseEntity getDynamicSecurityAnalysisProvider(@PathVariable(" return ResponseEntity.ok().body(studyService.getDynamicSecurityAnalysisProvider(studyUuid)); } + @PostMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/provider") + @Operation(summary = "Set dynamic margin calculation provider for the specified study, no body means reset to default provider") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation provider is set")}) + public ResponseEntity setDynamicMarginCalculationProvider(@PathVariable("studyUuid") UUID studyUuid, + @RequestBody(required = false) String provider, + @RequestHeader(HEADER_USER_ID) String userId) { + studyService.updateDynamicMarginCalculationProvider(studyUuid, provider, userId); + return ResponseEntity.ok().build(); + } + + @GetMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/provider") + @Operation(summary = "Get dynamic margin calculation provider for a specified study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation provider is returned")}) + public ResponseEntity getDynamicMarginCalculationProvider(@PathVariable("studyUuid") UUID studyUuid) { + return ResponseEntity.ok().body(studyService.getDynamicMarginCalculationProvider(studyUuid)); + } + @PostMapping(value = "/studies/{studyUuid}/short-circuit-analysis/parameters", consumes = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "set short-circuit analysis parameters on study, reset to default ones if empty body") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The short-circuit analysis parameters are set"), @@ -2068,6 +2087,57 @@ public ResponseEntity getDynamicSecurityAnalysisStatus(@Parameter(descri // --- Dynamic Security Analysis Endpoints END --- // + // --- Dynamic Margin Calculation Endpoints BEGIN --- // + + @PostMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/parameters") + @Operation(summary = "Set dynamic margin calculation parameters on study, reset to default one if empty body") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation parameters are set")}) + public ResponseEntity setDynamicMarginCalculationParameters( + @PathVariable("studyUuid") UUID studyUuid, + @RequestBody(required = false) String dmcParameter, + @RequestHeader(HEADER_USER_ID) String userId) { + return studyService.setDynamicMarginCalculationParameters(studyUuid, dmcParameter, userId) ? + ResponseEntity.noContent().build() : + ResponseEntity.ok().build(); + } + + @GetMapping(value = "/studies/{studyUuid}/dynamic-margin-calculation/parameters") + @Operation(summary = "Get dynamic margin calculation parameters on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation parameters")}) + public ResponseEntity getDynamicMarginCalculationParameters( + @PathVariable("studyUuid") UUID studyUuid) { + return ResponseEntity.ok().body(studyService.getDynamicMarginCalculationParameters(studyUuid)); + } + + @PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/dynamic-margin-calculation/run") + @Operation(summary = "run dynamic margin calculation on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The dynamic margin calculation has started")}) + public ResponseEntity runDynamicMarginCalculation(@Parameter(description = "studyUuid") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "root network id") @PathVariable("rootNetworkUuid") UUID rootNetworkUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid, + @Parameter(description = "debug") @RequestParam(name = "debug", required = false, defaultValue = "false") boolean debug, + @RequestHeader(HEADER_USER_ID) String userId) throws JsonProcessingException { + studyService.assertIsNodeNotReadOnly(nodeUuid); + studyService.assertCanRunOnConstructionNode(studyUuid, nodeUuid, List.of(DYNAWO_PROVIDER), studyService::getDynamicMarginCalculationProvider); + studyService.runDynamicMarginCalculation(studyUuid, nodeUuid, rootNetworkUuid, userId, debug); + return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).build(); + } + + @GetMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/dynamic-margin-calculation/status") + @Operation(summary = "Get the status of dynamic margin calculation result on study") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The status of dynamic margin calculation result"), + @ApiResponse(responseCode = "204", description = "No dynamic margin calculation status"), + @ApiResponse(responseCode = "404", description = "The dynamic margin calculation has not been found")}) + public ResponseEntity getDynamicMarginCalculationStatus(@Parameter(description = "study UUID") @PathVariable("studyUuid") UUID studyUuid, + @Parameter(description = "root network id") @PathVariable("rootNetworkUuid") UUID rootNetworkUuid, + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid) { + DynamicMarginCalculationStatus result = rootNetworkNodeInfoService.getDynamicMarginCalculationStatus(nodeUuid, rootNetworkUuid); + return result != null ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(result.name()) : + ResponseEntity.noContent().build(); + } + + // --- Dynamic Margin Calculation Endpoints END --- // + @GetMapping(value = "/studies/{studyUuid}/security-analysis/parameters") @Operation(summary = "Get security analysis parameters on study") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis parameters")}) diff --git a/src/main/java/org/gridsuite/study/server/dto/ComputationType.java b/src/main/java/org/gridsuite/study/server/dto/ComputationType.java index d39169792c..aed700802a 100644 --- a/src/main/java/org/gridsuite/study/server/dto/ComputationType.java +++ b/src/main/java/org/gridsuite/study/server/dto/ComputationType.java @@ -1,8 +1,11 @@ package org.gridsuite.study.server.dto; import lombok.Getter; +import org.apache.commons.lang3.exception.UncheckedException; import org.gridsuite.study.server.notification.NotificationService; +import java.util.UUID; + @Getter public enum ComputationType { LOAD_FLOW("Load flow", "loadFlowResultUuid", @@ -17,6 +20,9 @@ public enum ComputationType { SHORT_CIRCUIT("Short circuit analysis", "shortCircuitAnalysisResultUuid", NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_STATUS, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_RESULT, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_FAILED), + SHORT_CIRCUIT_ONE_BUS("One bus Short circuit analysis", "oneBusShortCircuitAnalysisResultUuid", + NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_RESULT, + NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_FAILED), VOLTAGE_INITIALIZATION("Voltage init", "voltageInitResultUuid", NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_RESULT, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_FAILED), @@ -26,9 +32,9 @@ public enum ComputationType { DYNAMIC_SECURITY_ANALYSIS("Dynamic security analysis", "dynamicSecurityAnalysisResultUuid", NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_RESULT, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_FAILED), - SHORT_CIRCUIT_ONE_BUS("One bus Short circuit analysis", "oneBusShortCircuitAnalysisResultUuid", - NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_RESULT, - NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_FAILED), + DYNAMIC_MARGIN_CALCULATION("Dynamic margin calculation", "dynamicMarginCalculationResultUuid", + NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_RESULT, + NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_FAILED), STATE_ESTIMATION("State estimation", "stateEstimationResultUuid", NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_RESULT, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_FAILED), @@ -49,4 +55,32 @@ public enum ComputationType { this.updateResultType = updateResultType; this.updateFailedType = updateFailedType; } + + public UUID getResultUuid(Object object) { + try { + // Transform fieldName (e.g., "loadFlowResultUuid") to getter ("getLoadFlowResultUuid") + String getterName = "get" + resultUuidLabel.substring(0, 1).toUpperCase() + resultUuidLabel.substring(1); + return (UUID) object.getClass().getMethod(getterName).invoke(object); + } catch (Exception e) { + throw new UncheckedException(e); + } + } + + private void updateResultUuid(Object object, UUID resultUuid, String updatePrefix) { + try { + // Transform fieldName (e.g., "loadFlowResultUuid") to setter ("setLoadFlowResultUuid") + String getterName = updatePrefix + resultUuidLabel.substring(0, 1).toUpperCase() + resultUuidLabel.substring(1); + object.getClass().getMethod(getterName, UUID.class).invoke(object, resultUuid); + } catch (Exception e) { + throw new UncheckedException(e); + } + } + + public void setResultUuid(Object object, UUID resultUuid) { + updateResultUuid(object, resultUuid, "set"); + } + + public void addResultUuid(Object object, UUID resultUuid) { + updateResultUuid(object, resultUuid, "add"); + } } diff --git a/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java b/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java index 0a0368a77a..d9a46ca7fa 100644 --- a/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java @@ -44,6 +44,8 @@ public class DeleteNodeInfos { private List dynamicSecurityAnalysisResultUuids = new ArrayList<>(); + private List dynamicMarginCalculationResultUuids = new ArrayList<>(); + private List stateEstimationResultUuids = new ArrayList<>(); private List pccMinResultUuids = new ArrayList<>(); @@ -80,6 +82,10 @@ public void addDynamicSecurityAnalysisResultUuid(UUID dynamicSecurityAnalysisRes dynamicSecurityAnalysisResultUuids.add(dynamicSecurityAnalysisResultUuid); } + public void addDynamicMarginCalculationResultUuid(UUID dynamicMarginCalculationResultUuid) { + dynamicMarginCalculationResultUuids.add(dynamicMarginCalculationResultUuid); + } + public void addSensitivityAnalysisResultUuid(UUID sensitivityAnalysisResultUuid) { sensitivityAnalysisResultUuids.add(sensitivityAnalysisResultUuid); } diff --git a/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java b/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java index d959ea16d8..ae3c24f609 100644 --- a/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/InvalidateNodeInfos.java @@ -40,6 +40,7 @@ public class InvalidateNodeInfos { private Set pccMinResultUuids = new HashSet<>(); private Set dynamicSimulationResultUuids = new HashSet<>(); private Set dynamicSecurityAnalysisResultUuids = new HashSet<>(); + private Set dynamicMarginCalculationResultUuids = new HashSet<>(); public List getNodeUuids() { return nodeUuids.stream().toList(); @@ -97,6 +98,10 @@ public List getDynamicSecurityAnalysisResultUuids() { return dynamicSecurityAnalysisResultUuids.stream().toList(); } + public List getDynamicMarginCalculationResultUuids() { + return dynamicMarginCalculationResultUuids.stream().toList(); + } + public void addReportUuid(UUID reportUuid) { reportUuids.add(reportUuid); } @@ -137,6 +142,10 @@ public void addDynamicSecurityAnalysisResultUuid(UUID dynamicSecurityAnalysisRes dynamicSecurityAnalysisResultUuids.add(dynamicSecurityAnalysisResultUuid); } + public void addDynamicMarginCalculationResultUuid(UUID dynamicMarginCalculationResultUuid) { + dynamicMarginCalculationResultUuids.add(dynamicMarginCalculationResultUuid); + } + public void addStateEstimationResultUuid(UUID stateEstimationResultUuid) { stateEstimationResultUuids.add(stateEstimationResultUuid); } @@ -170,5 +179,6 @@ public void add(InvalidateNodeInfos invalidateNodeInfos) { pccMinResultUuids.addAll(invalidateNodeInfos.getPccMinResultUuids()); dynamicSimulationResultUuids.addAll(invalidateNodeInfos.getDynamicSimulationResultUuids()); dynamicSecurityAnalysisResultUuids.addAll(invalidateNodeInfos.getDynamicSecurityAnalysisResultUuids()); + dynamicMarginCalculationResultUuids.addAll(invalidateNodeInfos.getDynamicMarginCalculationResultUuids()); } } diff --git a/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java b/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java index a983f975fd..41bc940eae 100644 --- a/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java +++ b/src/main/java/org/gridsuite/study/server/dto/RootNetworkNodeInfo.java @@ -48,6 +48,8 @@ public class RootNetworkNodeInfo { private UUID dynamicSecurityAnalysisResultUuid; + private UUID dynamicMarginCalculationResultUuid; + private UUID stateEstimationResultUuid; private UUID pccMinResultUuid; @@ -69,6 +71,7 @@ public RootNetworkNodeInfoEntity toEntity() { .sensitivityAnalysisResultUuid(sensitivityAnalysisResultUuid) .dynamicSimulationResultUuid(dynamicSimulationResultUuid) .dynamicSecurityAnalysisResultUuid(dynamicSecurityAnalysisResultUuid) + .dynamicMarginCalculationResultUuid(dynamicMarginCalculationResultUuid) .stateEstimationResultUuid(stateEstimationResultUuid) .pccMinResultUuid(pccMinResultUuid) .nodeBuildStatus(nodeBuildStatus.toEntity()) diff --git a/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java b/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java index e24769027b..a71ca3fd27 100644 --- a/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/UserProfileInfos.java @@ -35,6 +35,9 @@ public class UserProfileInfos { // note: this parameter is not managed by user-admin-server yet private UUID dynamicSecurityAnalysisParameterId; + // note: this parameter is not managed by user-admin-server yet + private UUID dynamicMarginCalculationParameterId; + private UUID voltageInitParameterId; Integer maxAllowedBuilds; diff --git a/src/main/java/org/gridsuite/study/server/dto/dynamicmargincalculation/DynamicMarginCalculationStatus.java b/src/main/java/org/gridsuite/study/server/dto/dynamicmargincalculation/DynamicMarginCalculationStatus.java new file mode 100644 index 0000000000..64bdd9c694 --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/dto/dynamicmargincalculation/DynamicMarginCalculationStatus.java @@ -0,0 +1,18 @@ +/* + * 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.study.server.dto.dynamicmargincalculation; + +/** + * @author Thang PHAM + */ +public enum DynamicMarginCalculationStatus { + NOT_DONE, + RUNNING, + SUCCEED, + FAILED +} diff --git a/src/main/java/org/gridsuite/study/server/dto/dynamicsecurityanalysis/DynamicSecurityAnalysisParametersInfos.java b/src/main/java/org/gridsuite/study/server/dto/dynamicsecurityanalysis/DynamicSecurityAnalysisParametersInfos.java deleted file mode 100644 index 5fb3a2e34b..0000000000 --- a/src/main/java/org/gridsuite/study/server/dto/dynamicsecurityanalysis/DynamicSecurityAnalysisParametersInfos.java +++ /dev/null @@ -1,40 +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.study.server.dto.dynamicsecurityanalysis; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.*; - -import java.util.List; -import java.util.UUID; - -/** - * @author Thang PHAM - */ -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class DynamicSecurityAnalysisParametersInfos { - private UUID id; - - private String provider; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Double scenarioDuration; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Double contingenciesStartTime; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private List contingencyListIds; - -} diff --git a/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java b/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java index 71209cfa50..6eb494ae15 100644 --- a/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java +++ b/src/main/java/org/gridsuite/study/server/networkmodificationtree/dto/NetworkModificationNode.java @@ -52,6 +52,8 @@ public class NetworkModificationNode extends AbstractNode { private UUID dynamicSecurityAnalysisResultUuid; + private UUID dynamicMarginCalculationResultUuid; + private UUID stateEstimationResultUuid; private UUID pccMinResultUuid; @@ -72,6 +74,7 @@ public void completeDtoFromRootNetworkNodeInfo(RootNetworkNodeInfoEntity rootNet this.setSensitivityAnalysisResultUuid(rootNetworkNodeInfoEntity.getSensitivityAnalysisResultUuid()); this.setDynamicSimulationResultUuid(rootNetworkNodeInfoEntity.getDynamicSimulationResultUuid()); this.setDynamicSecurityAnalysisResultUuid(rootNetworkNodeInfoEntity.getDynamicSecurityAnalysisResultUuid()); + this.setDynamicMarginCalculationResultUuid(rootNetworkNodeInfoEntity.getDynamicMarginCalculationResultUuid()); this.setStateEstimationResultUuid(rootNetworkNodeInfoEntity.getStateEstimationResultUuid()); this.setPccMinResultUuid(rootNetworkNodeInfoEntity.getPccMinResultUuid()); this.setNodeBuildStatus(rootNetworkNodeInfoEntity.getNodeBuildStatus().toDto()); diff --git a/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java b/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java index 92062ad5a0..9a02f100c5 100644 --- a/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java +++ b/src/main/java/org/gridsuite/study/server/networkmodificationtree/entities/RootNetworkNodeInfoEntity.java @@ -96,6 +96,9 @@ public class RootNetworkNodeInfoEntity { @Column(name = "dynamicSecurityAnalysisResultUuid") private UUID dynamicSecurityAnalysisResultUuid; + @Column(name = "dynamicMarginCalculationResultUuid") + private UUID dynamicMarginCalculationResultUuid; + @Column(name = "stateEstimationResultUuid") private UUID stateEstimationResultUuid; @@ -126,6 +129,7 @@ public RootNetworkNodeInfo toDto() { .modificationReports(modificationReports) .dynamicSimulationResultUuid(dynamicSimulationResultUuid) .dynamicSecurityAnalysisResultUuid(dynamicSecurityAnalysisResultUuid) + .dynamicMarginCalculationResultUuid(dynamicMarginCalculationResultUuid) .loadFlowResultUuid(loadFlowResultUuid) .loadFlowWithRatioTapChangers(loadFlowWithRatioTapChangers) .nodeBuildStatus(nodeBuildStatus.toDto()) diff --git a/src/main/java/org/gridsuite/study/server/notification/NotificationService.java b/src/main/java/org/gridsuite/study/server/notification/NotificationService.java index 8a8ee38127..28ecdef8f4 100644 --- a/src/main/java/org/gridsuite/study/server/notification/NotificationService.java +++ b/src/main/java/org/gridsuite/study/server/notification/NotificationService.java @@ -75,6 +75,9 @@ public class NotificationService { public static final String UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_FAILED = "dynamicSecurityAnalysis_failed"; public static final String UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_RESULT = "dynamicSecurityAnalysisResult"; public static final String UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS = "dynamicSecurityAnalysis_status"; + public static final String UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_FAILED = "dynamicMarginCalculation_failed"; + public static final String UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_RESULT = "dynamicMarginCalculationResult"; + public static final String UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS = "dynamicMarginCalculation_status"; public static final String UPDATE_TYPE_VOLTAGE_INIT_RESULT = "voltageInitResult"; public static final String UPDATE_TYPE_VOLTAGE_INIT_STATUS = "voltageInit_status"; public static final String UPDATE_TYPE_VOLTAGE_INIT_FAILED = "voltageInit_failed"; @@ -141,6 +144,20 @@ public class NotificationService { private static final Logger MESSAGE_OUTPUT_LOGGER = LoggerFactory.getLogger(CATEGORY_BROKER_OUTPUT); + public static final List ALL_COMPUTATION_STATUS = List.of( + UPDATE_TYPE_LOADFLOW_STATUS, + UPDATE_TYPE_SECURITY_ANALYSIS_STATUS, + UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS, + UPDATE_TYPE_SHORT_CIRCUIT_STATUS, + UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS, + UPDATE_TYPE_VOLTAGE_INIT_STATUS, + UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS, + UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS, + UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS, + UPDATE_TYPE_STATE_ESTIMATION_STATUS, + UPDATE_TYPE_PCC_MIN_STATUS + ); + private final StreamBridge updatePublisher; private final ObjectMapper objectMapper; diff --git a/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java b/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java index 1ef3d03e76..fc26ad8030 100644 --- a/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java +++ b/src/main/java/org/gridsuite/study/server/repository/StudyEntity.java @@ -83,6 +83,9 @@ public class StudyEntity extends AbstractManuallyAssignedIdentifierEntity @Column(name = "dynamicSecurityAnalysisParametersUuid") private UUID dynamicSecurityAnalysisParametersUuid; + @Column(name = "dynamicMarginCalculationParametersUuid") + private UUID dynamicMarginCalculationParametersUuid; + @Column(name = "voltageInitParametersUuid") private UUID voltageInitParametersUuid; diff --git a/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java b/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java index 61919ef07b..3a03c19b5c 100644 --- a/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java +++ b/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java @@ -28,6 +28,8 @@ public interface RootNetworkNodeInfoRepository extends JpaRepository findAllByDynamicSecurityAnalysisResultUuidNotNull(); + List findAllByDynamicMarginCalculationResultUuidNotNull(); + List findAllBySecurityAnalysisResultUuidNotNull(); List findAllBySensitivityAnalysisResultUuidNotNull(); diff --git a/src/main/java/org/gridsuite/study/server/service/ConsumerService.java b/src/main/java/org/gridsuite/study/server/service/ConsumerService.java index 200bb89151..fef8a5fd26 100644 --- a/src/main/java/org/gridsuite/study/server/service/ConsumerService.java +++ b/src/main/java/org/gridsuite/study/server/service/ConsumerService.java @@ -23,6 +23,7 @@ import org.gridsuite.study.server.networkmodificationtree.dto.BuildStatus; import org.gridsuite.study.server.networkmodificationtree.dto.NodeBuildStatus; import org.gridsuite.study.server.notification.NotificationService; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; @@ -71,6 +72,7 @@ public class ConsumerService { private final RootNetworkNodeInfoService rootNetworkNodeInfoService; private final VoltageInitService voltageInitService; private final DynamicSecurityAnalysisService dynamicSecurityAnalysisService; + private final DynamicMarginCalculationService dynamicMarginCalculationService; private final StateEstimationService stateEstimationService; private final PccMinService pccMinService; @@ -87,6 +89,7 @@ public ConsumerService(ObjectMapper objectMapper, RootNetworkNodeInfoService rootNetworkNodeInfoService, VoltageInitService voltageInitService, DynamicSecurityAnalysisService dynamicSecurityAnalysisService, + DynamicMarginCalculationService dynamicMarginCalculationService, StateEstimationService stateEstimationService, PccMinService pccMinService) { this.objectMapper = objectMapper; this.notificationService = notificationService; @@ -101,6 +104,7 @@ public ConsumerService(ObjectMapper objectMapper, this.rootNetworkNodeInfoService = rootNetworkNodeInfoService; this.voltageInitService = voltageInitService; this.dynamicSecurityAnalysisService = dynamicSecurityAnalysisService; + this.dynamicMarginCalculationService = dynamicMarginCalculationService; this.stateEstimationService = stateEstimationService; this.pccMinService = pccMinService; } @@ -290,6 +294,7 @@ private void insertStudy(UUID studyUuid, String userId, NetworkInfos networkInfo UUID networkVisualizationParametersUuid = createDefaultNetworkVisualizationParameters(userId, userProfileInfos); UUID voltageInitParametersUuid = createDefaultVoltageInitParameters(userId, userProfileInfos); UUID dynamicSecurityAnalysisParametersUuid = createDefaultDynamicSecurityAnalysisParameters(userId, userProfileInfos); + UUID dynamicMarginCalculationParametersUuid = createDefaultDynamicMarginCalculationParameters(userId, userProfileInfos); UUID stateEstimationParametersUuid = createDefaultStateEstimationParameters(); UUID pccMinParametersUuid = createDefaultPccMinParameters(); UUID spreadsheetConfigCollectionUuid = createDefaultSpreadsheetConfigCollection(userId, userProfileInfos); @@ -298,7 +303,8 @@ private void insertStudy(UUID studyUuid, String userId, NetworkInfos networkInfo studyService.insertStudy(studyUuid, userId, networkInfos, caseInfos, loadFlowParametersUuid, shortCircuitParametersUuid, DynamicSimulationService.toEntity(dynamicSimulationParameters, objectMapper), voltageInitParametersUuid, securityAnalysisParametersUuid, sensitivityAnalysisParametersUuid, - networkVisualizationParametersUuid, dynamicSecurityAnalysisParametersUuid, stateEstimationParametersUuid, pccMinParametersUuid, spreadsheetConfigCollectionUuid, diagramGridLayoutUuid, + networkVisualizationParametersUuid, dynamicSecurityAnalysisParametersUuid, dynamicMarginCalculationParametersUuid, + stateEstimationParametersUuid, pccMinParametersUuid, spreadsheetConfigCollectionUuid, diagramGridLayoutUuid, importParameters, importReportUuid); } @@ -442,6 +448,26 @@ private UUID createDefaultDynamicSecurityAnalysisParameters(String userId, UserP } } + private UUID createDefaultDynamicMarginCalculationParameters(String userId, UserProfileInfos userProfileInfos) { + if (userProfileInfos != null && userProfileInfos.getDynamicMarginCalculationParameterId() != null) { + // try to access/duplicate the user profile Dynamic Margin Calculation parameters + try { + return dynamicMarginCalculationService.duplicateParameters(userProfileInfos.getDynamicMarginCalculationParameterId()); + } catch (Exception e) { + // TODO try to report a log in Root subreporter ? + LOGGER.error(String.format("Could not duplicate dynamic margin calculation parameters with id '%s' from user/profile '%s/%s'. Using default parameters", + userProfileInfos.getDynamicMarginCalculationParameterId(), userId, userProfileInfos.getName()), e); + } + } + // no profile, or no/bad dynamic margin calculation parameters in profile => use default values + try { + return dynamicMarginCalculationService.createDefaultParameters(); + } catch (final Exception e) { + LOGGER.error("Error while creating default parameters for dynamic margin calculation", e); + return null; + } + } + private UUID createDefaultStateEstimationParameters() { try { return stateEstimationService.createDefaultStateEstimationParameters(); @@ -520,12 +546,9 @@ public void consumeCalculationFailed(Message msg, ComputationType comput String userId = msg.getHeaders().get(HEADER_USER_ID, String.class); UUID resultUuid = null; - var computationsToReset = List.of(DYNAMIC_SIMULATION, DYNAMIC_SECURITY_ANALYSIS); - if (!computationsToReset.contains(computationType)) { - String resultId = msg.getHeaders().get(RESULT_UUID, String.class); - if (resultId != null) { - resultUuid = UUID.fromString(resultId); - } + String resultId = msg.getHeaders().get(RESULT_UUID, String.class); + if (resultId != null) { + resultUuid = UUID.fromString(resultId); } if (!Strings.isBlank(receiver)) { NodeReceiver receiverObj = null; @@ -705,6 +728,26 @@ public Consumer> consumeDsaFailed() { return message -> consumeCalculationFailed(message, DYNAMIC_SECURITY_ANALYSIS); } + @Bean + public Consumer> consumeDmcDebug() { + return message -> consumeCalculationDebug(message, DYNAMIC_MARGIN_CALCULATION); + } + + @Bean + public Consumer> consumeDmcResult() { + return message -> consumeCalculationResult(message, DYNAMIC_MARGIN_CALCULATION); + } + + @Bean + public Consumer> consumeDmcStopped() { + return message -> consumeCalculationStopped(message, DYNAMIC_MARGIN_CALCULATION); + } + + @Bean + public Consumer> consumeDmcFailed() { + return message -> consumeCalculationFailed(message, DYNAMIC_MARGIN_CALCULATION); + } + @Bean public Consumer> consumeSaResult() { return message -> consumeCalculationResult(message, SECURITY_ANALYSIS); diff --git a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java index d93aadac9f..9aaa8d2e85 100644 --- a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java +++ b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java @@ -9,15 +9,16 @@ import com.powsybl.timeseries.DoubleTimeSeries; import lombok.NonNull; import org.apache.commons.lang3.StringUtils; -import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.dto.*; import org.gridsuite.study.server.dto.computation.LoadFlowComputationInfos; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; import org.gridsuite.study.server.dto.dynamicsecurityanalysis.DynamicSecurityAnalysisStatus; import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationStatus; import org.gridsuite.study.server.dto.modification.ModificationApplicationContext; import org.gridsuite.study.server.dto.sensianalysis.SensitivityAnalysisCsvFileInfos; import org.gridsuite.study.server.dto.timeseries.TimeSeriesMetadataInfos; import org.gridsuite.study.server.dto.timeseries.TimelineEventInfos; +import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.networkmodificationtree.dto.BuildStatus; import org.gridsuite.study.server.networkmodificationtree.entities.NetworkModificationNodeInfoEntity; import org.gridsuite.study.server.networkmodificationtree.entities.NetworkModificationNodeType; @@ -27,6 +28,7 @@ import org.gridsuite.study.server.repository.networkmodificationtree.NetworkModificationNodeInfoRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; import org.gridsuite.study.server.service.securityanalysis.SecurityAnalysisResultType; @@ -45,9 +47,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*; import static org.gridsuite.study.server.dto.ComputationType.*; import static org.gridsuite.study.server.dto.InvalidateNodeTreeParameters.ComputationsInvalidationMode; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*; /** * @author Slimane amar new StudyException(NOT_FOUND, "Root network not found")); - switch (computationType) { - case LOAD_FLOW -> rootNetworkNodeInfoEntity.setLoadFlowResultUuid(computationResultUuid); - case SECURITY_ANALYSIS -> rootNetworkNodeInfoEntity.setSecurityAnalysisResultUuid(computationResultUuid); - case SENSITIVITY_ANALYSIS -> - rootNetworkNodeInfoEntity.setSensitivityAnalysisResultUuid(computationResultUuid); - case SHORT_CIRCUIT -> rootNetworkNodeInfoEntity.setShortCircuitAnalysisResultUuid(computationResultUuid); - case SHORT_CIRCUIT_ONE_BUS -> - rootNetworkNodeInfoEntity.setOneBusShortCircuitAnalysisResultUuid(computationResultUuid); - case VOLTAGE_INITIALIZATION -> rootNetworkNodeInfoEntity.setVoltageInitResultUuid(computationResultUuid); - case DYNAMIC_SIMULATION -> rootNetworkNodeInfoEntity.setDynamicSimulationResultUuid(computationResultUuid); - case DYNAMIC_SECURITY_ANALYSIS -> rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(computationResultUuid); - case STATE_ESTIMATION -> rootNetworkNodeInfoEntity.setStateEstimationResultUuid(computationResultUuid); - case PCC_MIN -> rootNetworkNodeInfoEntity.setPccMinResultUuid(computationResultUuid); + updateComputationResultUuid(rootNetworkNodeInfoEntity, computationResultUuid, computationType); + } + + private void updateComputationResultUuid(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, UUID computationResultUuid, ComputationType computationType) { + computationType.setResultUuid(rootNetworkNodeInfoEntity, computationResultUuid); + if (computationType == LOAD_FLOW && computationResultUuid == null) { // particular in case of invalidating a node + rootNetworkNodeInfoEntity.setLoadFlowWithRatioTapChangers(null); } } @@ -169,8 +168,12 @@ public List getAllWithRootNetworkByNodeInfoId(UUID no return rootNetworkNodeInfoRepository.findAllWithRootNetworkByNodeInfoId(nodeUuid); } + private void addComputationResultUuid(DeleteNodeInfos deleteNodeInfos, UUID computationResultUuid, ComputationType computationType) { + computationType.addResultUuid(deleteNodeInfos, computationResultUuid); + } + public void fillDeleteNodeInfo(UUID nodeUuid, DeleteNodeInfos deleteNodeInfos) { - //get all rootnetworknodeinfo info linked to node + //get all rootNetworkNodeInfo info linked to node List rootNetworkNodeInfoEntities = rootNetworkNodeInfoRepository.findAllWithRootNetworkByNodeInfoId(nodeUuid); rootNetworkNodeInfoEntities.forEach(rootNetworkNodeInfoEntity -> { rootNetworkNodeInfoEntity.getModificationReports().forEach((key, value) -> deleteNodeInfos.addReportUuid(value)); @@ -182,55 +185,10 @@ public void fillDeleteNodeInfo(UUID nodeUuid, DeleteNodeInfos deleteNodeInfos) { deleteNodeInfos.addVariantId(networkUuid, variantId); } - UUID loadFlowResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, LOAD_FLOW); - if (loadFlowResultUuid != null) { - deleteNodeInfos.addLoadFlowResultUuid(loadFlowResultUuid); - } - - UUID securityAnalysisResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, SECURITY_ANALYSIS); - if (securityAnalysisResultUuid != null) { - deleteNodeInfos.addSecurityAnalysisResultUuid(securityAnalysisResultUuid); - } - - UUID sensitivityAnalysisResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, SENSITIVITY_ANALYSIS); - if (sensitivityAnalysisResultUuid != null) { - deleteNodeInfos.addSensitivityAnalysisResultUuid(sensitivityAnalysisResultUuid); - } - - UUID shortCircuitAnalysisResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, SHORT_CIRCUIT); - if (shortCircuitAnalysisResultUuid != null) { - deleteNodeInfos.addShortCircuitAnalysisResultUuid(shortCircuitAnalysisResultUuid); - } - - UUID oneBusShortCircuitAnalysisResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, SHORT_CIRCUIT_ONE_BUS); - if (oneBusShortCircuitAnalysisResultUuid != null) { - deleteNodeInfos.addOneBusShortCircuitAnalysisResultUuid(oneBusShortCircuitAnalysisResultUuid); - } - - UUID voltageInitResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, VOLTAGE_INITIALIZATION); - if (voltageInitResultUuid != null) { - deleteNodeInfos.addVoltageInitResultUuid(voltageInitResultUuid); - } - - UUID dynamicSimulationResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, DYNAMIC_SIMULATION); - if (dynamicSimulationResultUuid != null) { - deleteNodeInfos.addDynamicSimulationResultUuid(dynamicSimulationResultUuid); - } - - UUID dynamicSecurityAnalysisResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, DYNAMIC_SECURITY_ANALYSIS); - if (dynamicSecurityAnalysisResultUuid != null) { - deleteNodeInfos.addDynamicSecurityAnalysisResultUuid(dynamicSecurityAnalysisResultUuid); - } - - UUID stateEstimationResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, STATE_ESTIMATION); - if (stateEstimationResultUuid != null) { - deleteNodeInfos.addStateEstimationResultUuid(stateEstimationResultUuid); - } - - UUID pccMinResultUuid = getComputationResultUuid(rootNetworkNodeInfoEntity, PCC_MIN); - if (pccMinResultUuid != null) { - deleteNodeInfos.addPccMinResultUuid(pccMinResultUuid); - } + Arrays.stream(ComputationType.values()).forEach(computationType -> { + Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, computationType)) + .ifPresent(resultUuid -> addComputationResultUuid(deleteNodeInfos, resultUuid, computationType)); + }); }); } @@ -338,7 +296,7 @@ private Set filterForExclusivelyOwnedReports( .collect(Collectors.toSet()); } - private static void invalidateBuildStatus(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, InvalidateNodeInfos invalidateNodeInfos) { + private void invalidateBuildStatus(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, InvalidateNodeInfos invalidateNodeInfos) { rootNetworkNodeInfoEntity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.NOT_BUILT)); rootNetworkNodeInfoEntity.setVariantId(UUID.randomUUID().toString()); rootNetworkNodeInfoEntity.setModificationReports(new HashMap<>()); @@ -346,34 +304,22 @@ private static void invalidateBuildStatus(RootNetworkNodeInfoEntity rootNetworkN invalidateNodeInfos.addNodeUuid(rootNetworkNodeInfoEntity.getNodeInfo().getIdNode()); } - private static void invalidateComputationResults(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, ComputationsInvalidationMode computationsInvalidationMode) { - if (!ComputationsInvalidationMode.isPreserveLoadFlowResults(computationsInvalidationMode)) { - rootNetworkNodeInfoEntity.setLoadFlowResultUuid(null); - rootNetworkNodeInfoEntity.setLoadFlowWithRatioTapChangers(null); - } - rootNetworkNodeInfoEntity.setSecurityAnalysisResultUuid(null); - rootNetworkNodeInfoEntity.setSensitivityAnalysisResultUuid(null); - rootNetworkNodeInfoEntity.setShortCircuitAnalysisResultUuid(null); - rootNetworkNodeInfoEntity.setOneBusShortCircuitAnalysisResultUuid(null); - rootNetworkNodeInfoEntity.setDynamicSimulationResultUuid(null); - rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(null); - if (!ComputationsInvalidationMode.isPreserveVoltageInitResults(computationsInvalidationMode)) { - rootNetworkNodeInfoEntity.setVoltageInitResultUuid(null); - } - rootNetworkNodeInfoEntity.setStateEstimationResultUuid(null); - rootNetworkNodeInfoEntity.setPccMinResultUuid(null); + private void invalidateComputationResults(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, ComputationsInvalidationMode computationsInvalidationMode) { + Arrays.stream(ComputationType.values()) + .filter(computationType -> !shouldPreserveComputationResult(computationType.name(), computationsInvalidationMode)) + .forEach(computationType -> updateComputationResultUuid(rootNetworkNodeInfoEntity, null, computationType)); Map computationReports = rootNetworkNodeInfoEntity.getComputationReports() .entrySet() .stream() - .filter(entry -> shouldPreserveComputationReport(entry.getKey(), computationsInvalidationMode)) + .filter(entry -> shouldPreserveComputationResult(entry.getKey(), computationsInvalidationMode)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); // Update the computation reports in the repository rootNetworkNodeInfoEntity.setComputationReports(computationReports); } - private static boolean shouldPreserveComputationReport(String computationType, ComputationsInvalidationMode computationsInvalidationMode) { + private static boolean shouldPreserveComputationResult(String computationType, ComputationsInvalidationMode computationsInvalidationMode) { return VOLTAGE_INITIALIZATION.name().equals(computationType) && ComputationsInvalidationMode.isPreserveVoltageInitResults(computationsInvalidationMode) || LOAD_FLOW.name().equals(computationType) && ComputationsInvalidationMode.isPreserveLoadFlowResults(computationsInvalidationMode); } @@ -382,41 +328,24 @@ private InvalidateNodeInfos getInvalidationComputationInfos(RootNetworkNodeInfoE InvalidateNodeInfos invalidateNodeInfos = new InvalidateNodeInfos(); rootNetworkNodeInfoEntity.getComputationReports().forEach((key, value) -> { - if (!shouldPreserveComputationReport(key, computationsInvalidationMode)) { + if (!shouldPreserveComputationResult(key, computationsInvalidationMode)) { invalidateNodeInfos.addReportUuid(value); } }); - fillComputationResultUuids(rootNetworkNodeInfoEntity, invalidateNodeInfos, computationsInvalidationMode); + Arrays.stream(ComputationType.values()) + .filter(computationType -> !shouldPreserveComputationResult(computationType.name(), computationsInvalidationMode)) + .forEach(computationType -> + Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, computationType)) + .ifPresent(resultUuid -> addComputationResultUuid(invalidateNodeInfos, resultUuid, computationType)) + ); return invalidateNodeInfos; } - private void fillComputationResultUuids(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, InvalidateNodeInfos invalidateNodeInfos, ComputationsInvalidationMode computationsInvalidationMode) { - if (!ComputationsInvalidationMode.isPreserveLoadFlowResults(computationsInvalidationMode)) { - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, LOAD_FLOW)) - .ifPresent(invalidateNodeInfos::addLoadFlowResultUuid); - } - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, SECURITY_ANALYSIS)) - .ifPresent(invalidateNodeInfos::addSecurityAnalysisResultUuid); - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, SENSITIVITY_ANALYSIS)) - .ifPresent(invalidateNodeInfos::addSensitivityAnalysisResultUuid); - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, SHORT_CIRCUIT)) - .ifPresent(invalidateNodeInfos::addShortCircuitAnalysisResultUuid); - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, SHORT_CIRCUIT_ONE_BUS)) - .ifPresent(invalidateNodeInfos::addOneBusShortCircuitAnalysisResultUuid); - if (!ComputationsInvalidationMode.isPreserveVoltageInitResults(computationsInvalidationMode)) { - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, VOLTAGE_INITIALIZATION)) - .ifPresent(invalidateNodeInfos::addVoltageInitResultUuid); - } - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, DYNAMIC_SIMULATION)) - .ifPresent(invalidateNodeInfos::addDynamicSimulationResultUuid); - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, DYNAMIC_SECURITY_ANALYSIS)) - .ifPresent(invalidateNodeInfos::addDynamicSecurityAnalysisResultUuid); - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, STATE_ESTIMATION)) - .ifPresent(invalidateNodeInfos::addStateEstimationResultUuid); - Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfoEntity, PCC_MIN)) - .ifPresent(invalidateNodeInfos::addPccMinResultUuid); + private void addComputationResultUuid(InvalidateNodeInfos invalidateNodeInfos, + UUID computationResultUuid, ComputationType computationType) { + computationType.addResultUuid(invalidateNodeInfos, computationResultUuid); } // TODO : Remove optionnal and throws ROOT_NETWORK_NOT_FOUND exception @@ -424,19 +353,12 @@ public Optional getRootNetworkNodeInfo(UUID nodeUuid, return rootNetworkNodeInfoRepository.findByNodeInfoIdAndRootNetworkId(nodeUuid, rootNetworkUuid); } - private static UUID getComputationResultUuid(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, ComputationType computationType) { - return switch (computationType) { - case LOAD_FLOW -> rootNetworkNodeInfoEntity.getLoadFlowResultUuid(); - case SECURITY_ANALYSIS -> rootNetworkNodeInfoEntity.getSecurityAnalysisResultUuid(); - case SENSITIVITY_ANALYSIS -> rootNetworkNodeInfoEntity.getSensitivityAnalysisResultUuid(); - case SHORT_CIRCUIT -> rootNetworkNodeInfoEntity.getShortCircuitAnalysisResultUuid(); - case SHORT_CIRCUIT_ONE_BUS -> rootNetworkNodeInfoEntity.getOneBusShortCircuitAnalysisResultUuid(); - case VOLTAGE_INITIALIZATION -> rootNetworkNodeInfoEntity.getVoltageInitResultUuid(); - case DYNAMIC_SIMULATION -> rootNetworkNodeInfoEntity.getDynamicSimulationResultUuid(); - case DYNAMIC_SECURITY_ANALYSIS -> rootNetworkNodeInfoEntity.getDynamicSecurityAnalysisResultUuid(); - case STATE_ESTIMATION -> rootNetworkNodeInfoEntity.getStateEstimationResultUuid(); - case PCC_MIN -> rootNetworkNodeInfoEntity.getPccMinResultUuid(); - }; + private UUID getComputationResultUuid(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, ComputationType computationType) { + return computationType.getResultUuid(rootNetworkNodeInfoEntity); + } + + private UUID getComputationResultUuid(RootNetworkNodeInfo rootNetworkNodeInfo, ComputationType computationType) { + return computationType.getResultUuid(rootNetworkNodeInfo); } public UUID getComputationResultUuid(UUID nodeUuid, UUID rootNetworkUuid, ComputationType computationType) { @@ -529,36 +451,13 @@ public void updateRootNetworkNode(UUID nodeUuid, UUID rootNetworkUuid, RootNetwo if (rootNetworkNodeInfo.getNodeBuildStatus() != null) { rootNetworkNodeInfoEntity.setNodeBuildStatus(rootNetworkNodeInfo.getNodeBuildStatus().toEntity()); } - if (rootNetworkNodeInfo.getLoadFlowResultUuid() != null) { - rootNetworkNodeInfoEntity.setLoadFlowResultUuid(rootNetworkNodeInfo.getLoadFlowResultUuid()); - } - if (rootNetworkNodeInfo.getSecurityAnalysisResultUuid() != null) { - rootNetworkNodeInfoEntity.setSecurityAnalysisResultUuid(rootNetworkNodeInfo.getSecurityAnalysisResultUuid()); - } - if (rootNetworkNodeInfo.getSensitivityAnalysisResultUuid() != null) { - rootNetworkNodeInfoEntity.setSensitivityAnalysisResultUuid(rootNetworkNodeInfo.getSensitivityAnalysisResultUuid()); - } - if (rootNetworkNodeInfo.getShortCircuitAnalysisResultUuid() != null) { - rootNetworkNodeInfoEntity.setShortCircuitAnalysisResultUuid(rootNetworkNodeInfo.getShortCircuitAnalysisResultUuid()); - } - if (rootNetworkNodeInfo.getOneBusShortCircuitAnalysisResultUuid() != null) { - rootNetworkNodeInfoEntity.setOneBusShortCircuitAnalysisResultUuid(rootNetworkNodeInfo.getOneBusShortCircuitAnalysisResultUuid()); - } - if (rootNetworkNodeInfo.getStateEstimationResultUuid() != null) { - rootNetworkNodeInfoEntity.setStateEstimationResultUuid(rootNetworkNodeInfo.getStateEstimationResultUuid()); - } - if (rootNetworkNodeInfo.getPccMinResultUuid() != null) { - rootNetworkNodeInfoEntity.setPccMinResultUuid(rootNetworkNodeInfo.getPccMinResultUuid()); - } - if (rootNetworkNodeInfo.getDynamicSimulationResultUuid() != null) { - rootNetworkNodeInfoEntity.setDynamicSimulationResultUuid(rootNetworkNodeInfo.getDynamicSimulationResultUuid()); - } - if (rootNetworkNodeInfo.getDynamicSecurityAnalysisResultUuid() != null) { - rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(rootNetworkNodeInfo.getDynamicSecurityAnalysisResultUuid()); - } - if (rootNetworkNodeInfo.getVoltageInitResultUuid() != null) { - rootNetworkNodeInfoEntity.setVoltageInitResultUuid(rootNetworkNodeInfo.getVoltageInitResultUuid()); - } + + Arrays.stream(ComputationType.values()) + .forEach(computationType -> + Optional.ofNullable(getComputationResultUuid(rootNetworkNodeInfo, computationType)) + .ifPresent(resultUuid -> updateComputationResultUuid(rootNetworkNodeInfoEntity, resultUuid, computationType)) + ); + if (rootNetworkNodeInfo.getModificationReports() != null) { rootNetworkNodeInfoEntity.setModificationReports(rootNetworkNodeInfo.getModificationReports()); } @@ -576,6 +475,7 @@ public void deleteRootNetworkNodeRemoteInfos(List rootNetwo studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getVoltageInitResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSimulationResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSecurityAnalysisResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsync(() -> dynamicMarginCalculationService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicMarginCalculationResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getStateEstimationResultUuid).filter(Objects::nonNull).toList())), studyServerExecutionService.runAsync(() -> pccMinService.deletePccMinResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getPccMinResultUuid).filter(Objects::nonNull).toList())) ); @@ -602,6 +502,7 @@ public void assertComputationNotRunning(UUID nodeUuid, UUID rootNetworkUuid) { securityAnalysisService.assertSecurityAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, SECURITY_ANALYSIS)); dynamicSimulationService.assertDynamicSimulationNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_SIMULATION)); dynamicSecurityAnalysisService.assertDynamicSecurityAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_SECURITY_ANALYSIS)); + dynamicMarginCalculationService.assertDynamicMarginCalculationNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION)); sensitivityAnalysisService.assertSensitivityAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, SENSITIVITY_ANALYSIS)); shortCircuitService.assertShortCircuitAnalysisNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, SHORT_CIRCUIT), getComputationResultUuid(nodeUuid, rootNetworkUuid, SHORT_CIRCUIT_ONE_BUS)); voltageInitService.assertVoltageInitNotRunning(getComputationResultUuid(nodeUuid, rootNetworkUuid, VOLTAGE_INITIALIZATION)); @@ -784,6 +685,12 @@ public DynamicSecurityAnalysisStatus getDynamicSecurityAnalysisStatus(UUID nodeU return dynamicSecurityAnalysisService.getStatus(resultUuid); } + @Transactional(readOnly = true) + public DynamicMarginCalculationStatus getDynamicMarginCalculationStatus(UUID nodeUuid, UUID rootNetworkUuid) { + UUID resultUuid = getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION); + return dynamicMarginCalculationService.getStatus(resultUuid); + } + public String getSensitivityAnalysisStatus(UUID nodeUuid, UUID rootNetworkUuid) { UUID resultUuid = getComputationResultUuid(nodeUuid, rootNetworkUuid, SENSITIVITY_ANALYSIS); return sensitivityAnalysisService.getSensitivityAnalysisStatus(resultUuid); diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index c215edb902..56daf7f096 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -16,9 +16,6 @@ import org.gridsuite.filter.globalfilter.GlobalFilter; import org.gridsuite.filter.utils.EquipmentType; import org.gridsuite.study.server.StudyConstants; -import org.gridsuite.study.server.dto.modification.*; -import org.gridsuite.study.server.dto.voltageinit.ContextInfos; -import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.dto.*; import org.gridsuite.study.server.dto.InvalidateNodeTreeParameters.ComputationsInvalidationMode; import org.gridsuite.study.server.dto.InvalidateNodeTreeParameters.InvalidationMode; @@ -32,13 +29,16 @@ import org.gridsuite.study.server.dto.dynamicsimulation.event.EventInfos; import org.gridsuite.study.server.dto.elasticsearch.EquipmentInfos; import org.gridsuite.study.server.dto.impacts.SimpleElementImpact; +import org.gridsuite.study.server.dto.modification.*; import org.gridsuite.study.server.dto.sequence.NodeSequenceType; +import org.gridsuite.study.server.dto.voltageinit.ContextInfos; import org.gridsuite.study.server.dto.voltageinit.parameters.StudyVoltageInitParameters; import org.gridsuite.study.server.dto.voltageinit.parameters.VoltageInitParametersInfos; import org.gridsuite.study.server.dto.workflow.AbstractWorkflowInfos; import org.gridsuite.study.server.dto.workflow.RerunLoadFlowInfos; import org.gridsuite.study.server.elasticsearch.EquipmentInfosService; import org.gridsuite.study.server.elasticsearch.StudyInfosService; +import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.networkmodificationtree.dto.*; import org.gridsuite.study.server.networkmodificationtree.entities.NetworkModificationNodeInfoEntity; import org.gridsuite.study.server.networkmodificationtree.entities.NodeEntity; @@ -50,6 +50,7 @@ import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkRequestEntity; import org.gridsuite.study.server.repository.voltageinit.StudyVoltageInitParametersEntity; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationEventService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; @@ -82,11 +83,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*; import static org.gridsuite.study.server.StudyConstants.BUS_ID_TO_ICC_VALUES; import static org.gridsuite.study.server.StudyConstants.CURRENT_LIMIT_VIOLATIONS_INFOS; import static org.gridsuite.study.server.dto.ComputationType.*; import static org.gridsuite.study.server.dto.InvalidateNodeTreeParameters.ALL_WITH_BLOCK_NODES; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*; +import static org.gridsuite.study.server.notification.NotificationService.ALL_COMPUTATION_STATUS; /** * @author Abdelsalem Hedhili @@ -125,6 +127,7 @@ public class StudyService { private final SecurityAnalysisService securityAnalysisService; private final DynamicSimulationService dynamicSimulationService; private final DynamicSecurityAnalysisService dynamicSecurityAnalysisService; + private final DynamicMarginCalculationService dynamicMarginCalculationService; private final SensitivityAnalysisService sensitivityAnalysisService; private final DynamicSimulationEventService dynamicSimulationEventService; private final StudyConfigService studyConfigService; @@ -150,6 +153,7 @@ public enum ReportType { SENSITIVITY_ANALYSIS("SensitivityAnalysis"), DYNAMIC_SIMULATION("DynamicSimulation"), DYNAMIC_SECURITY_ANALYSIS("DynamicSecurityAnalysis"), + DYNAMIC_MARGIN_CALCULATION("DynamicMarginCalculation"), VOLTAGE_INITIALIZATION("VoltageInit"), STATE_ESTIMATION("StateEstimation"), PCC_MIN("PccMin"); @@ -190,6 +194,7 @@ public StudyService( SensitivityAnalysisService sensitivityAnalysisService, DynamicSimulationService dynamicSimulationService, DynamicSecurityAnalysisService dynamicSecurityAnalysisService, + DynamicMarginCalculationService dynamicMarginCalculationService, VoltageInitService voltageInitService, DynamicSimulationEventService dynamicSimulationEventService, StudyConfigService studyConfigService, @@ -227,6 +232,7 @@ public StudyService( this.caseService = caseService; this.dynamicSimulationService = dynamicSimulationService; this.dynamicSecurityAnalysisService = dynamicSecurityAnalysisService; + this.dynamicMarginCalculationService = dynamicMarginCalculationService; this.voltageInitService = voltageInitService; this.dynamicSimulationEventService = dynamicSimulationEventService; this.studyConfigService = studyConfigService; @@ -543,6 +549,7 @@ private Optional doDeleteStudyIfNotCreationInProgress(UUID stu removeVoltageInitParameters(s.getVoltageInitParametersUuid()); removeSensitivityAnalysisParameters(s.getSensitivityAnalysisParametersUuid()); removeDynamicSecurityAnalysisParameters(s.getDynamicSecurityAnalysisParametersUuid()); + removeDynamicMarginCalculationParameters(s.getDynamicMarginCalculationParametersUuid()); removeNetworkVisualizationParameters(s.getNetworkVisualizationParametersUuid()); removeStateEstimationParameters(s.getStateEstimationParametersUuid()); removePccMinParameters(s.getPccMinParametersUuid()); @@ -615,7 +622,8 @@ public void deleteStudyIfNotCreationInProgress(UUID studyUuid) { public CreatedStudyBasicInfos insertStudy(UUID studyUuid, String userId, NetworkInfos networkInfos, CaseInfos caseInfos, UUID loadFlowParametersUuid, UUID shortCircuitParametersUuid, DynamicSimulationParametersEntity dynamicSimulationParametersEntity, UUID voltageInitParametersUuid, UUID securityAnalysisParametersUuid, UUID sensitivityAnalysisParametersUuid, - UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, + UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID dynamicMarginCalculationParametersUuid, + UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, UUID spreadsheetConfigCollectionUuid, UUID diagramGridLayoutUuid, Map importParameters, UUID importReportUuid) { Objects.requireNonNull(studyUuid); Objects.requireNonNull(userId); @@ -629,7 +637,8 @@ public CreatedStudyBasicInfos insertStudy(UUID studyUuid, String userId, Network caseInfos, loadFlowParametersUuid, shortCircuitParametersUuid, dynamicSimulationParametersEntity, voltageInitParametersUuid, securityAnalysisParametersUuid, - sensitivityAnalysisParametersUuid, networkVisualizationParametersUuid, dynamicSecurityAnalysisParametersUuid, + sensitivityAnalysisParametersUuid, networkVisualizationParametersUuid, + dynamicSecurityAnalysisParametersUuid, dynamicMarginCalculationParametersUuid, stateEstimationParametersUuid, pccMinParametersUuid, spreadsheetConfigCollectionUuid, diagramGridLayoutUuid, importParameters, importReportUuid); // Need to deal with the study creation (with a default root network ?) @@ -1230,11 +1239,13 @@ public boolean setLoadFlowParameters(UUID studyUuid, String parameters, String u invalidateSensitivityAnalysisStatusOnAllNodes(studyUuid); invalidateDynamicSimulationStatusOnAllNodes(studyUuid); invalidateDynamicSecurityAnalysisStatusOnAllNodes(studyUuid); + invalidateDynamicMarginCalculationStatusOnAllNodes(studyUuid); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); + notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); notificationService.emitElementUpdated(studyUuid, userId); notificationService.emitComputationParamsChanged(studyUuid, LOAD_FLOW); return userProfileIssue; @@ -1317,7 +1328,7 @@ public String getDefaultDynamicSecurityAnalysisProvider(String userId) { return dynamicSecurityAnalysisService.getProvider(userProfileInfos.getDynamicSecurityAnalysisParameterId()); } catch (Exception e) { LOGGER.error(String.format("Could not get dynamic security analysis provider with id '%s' from user/profile '%s/%s'. Using default provider", - userProfileInfos.getLoadFlowParameterId(), userId, userProfileInfos.getName()), e); + userProfileInfos.getDynamicSecurityAnalysisParameterId(), userId, userProfileInfos.getName()), e); // in case of read error (ex: wrong/dangling uuid in the profile), move on with default provider below } } @@ -1340,6 +1351,37 @@ public void updateDynamicSecurityAnalysisProvider(UUID studyUuid, String provide }); } + public String getDefaultDynamicMarginCalculationProvider(String userId) { + if (userId != null) { + UserProfileInfos userProfileInfos = userAdminService.getUserProfile(userId); + if (userProfileInfos.getDynamicMarginCalculationParameterId() != null) { + try { + return dynamicMarginCalculationService.getProvider(userProfileInfos.getDynamicMarginCalculationParameterId()); + } catch (Exception e) { + LOGGER.error(String.format("Could not get dynamic margin calculation provider with id '%s' from user/profile '%s/%s'. Using default provider", + userProfileInfos.getDynamicMarginCalculationParameterId(), userId, userProfileInfos.getName()), e); + // in case of read error (ex: wrong/dangling uuid in the profile), move on with default provider below + } + } + } + return dynamicMarginCalculationService.getDefaultProvider(); + } + + public String getDynamicMarginCalculationProvider(UUID studyUuid) { + StudyEntity studyEntity = getStudy(studyUuid); + return dynamicMarginCalculationService.getProvider(studyEntity.getDynamicMarginCalculationParametersUuid()); + } + + public void updateDynamicMarginCalculationProvider(UUID studyUuid, String provider, String userId) { + updateProvider(studyUuid, userId, studyEntity -> { + dynamicMarginCalculationService.updateProvider(studyEntity.getDynamicMarginCalculationParametersUuid(), provider); + invalidateDynamicMarginCalculationStatusOnAllNodes(studyUuid); + notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); + notificationService.emitComputationParamsChanged(studyUuid, DYNAMIC_MARGIN_CALCULATION); + + }); + } + @Transactional public String getShortCircuitParametersInfo(UUID studyUuid) { StudyEntity studyEntity = getStudy(studyUuid); @@ -1557,6 +1599,10 @@ public void invalidateDynamicSecurityAnalysisStatusOnAllNodes(UUID studyUuid) { dynamicSecurityAnalysisService.invalidateStatus(rootNetworkNodeInfoService.getComputationResultUuids(studyUuid, DYNAMIC_SECURITY_ANALYSIS)); } + public void invalidateDynamicMarginCalculationStatusOnAllNodes(UUID studyUuid) { + dynamicMarginCalculationService.invalidateStatus(rootNetworkNodeInfoService.getComputationResultUuids(studyUuid, DYNAMIC_MARGIN_CALCULATION)); + } + public void invalidateAllStudyLoadFlowStatus(UUID studyUuid) { invalidateSecurityNodeTreeWithLoadFlowResults(studyUuid); invalidateLoadFlowStatusOnAllNodes(studyUuid); @@ -1612,7 +1658,8 @@ private StudyEntity saveStudyThenCreateBasicTree(UUID studyUuid, NetworkInfos ne CaseInfos caseInfos, UUID loadFlowParametersUuid, UUID shortCircuitParametersUuid, DynamicSimulationParametersEntity dynamicSimulationParametersEntity, UUID voltageInitParametersUuid, UUID securityAnalysisParametersUuid, UUID sensitivityAnalysisParametersUuid, - UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, + UUID networkVisualizationParametersUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID dynamicMarginCalculationParametersUuid, + UUID stateEstimationParametersUuid, UUID pccMinParametersUuid, UUID spreadsheetConfigCollectionUuid, UUID diagramGridLayoutUuid, Map importParameters, UUID importReportUuid) { StudyEntity studyEntity = StudyEntity.builder() @@ -1627,6 +1674,7 @@ private StudyEntity saveStudyThenCreateBasicTree(UUID studyUuid, NetworkInfos ne .voltageInitParameters(new StudyVoltageInitParametersEntity()) .networkVisualizationParametersUuid(networkVisualizationParametersUuid) .dynamicSecurityAnalysisParametersUuid(dynamicSecurityAnalysisParametersUuid) + .dynamicMarginCalculationParametersUuid(dynamicMarginCalculationParametersUuid) .stateEstimationParametersUuid(stateEstimationParametersUuid) .pccMinParametersUuid(pccMinParametersUuid) .spreadsheetConfigCollectionUuid(spreadsheetConfigCollectionUuid) @@ -2307,6 +2355,7 @@ private CompletableFuture deleteInvalidationInfos(InvalidateNodeInfos inva studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(invalidateNodeInfos.getVoltageInitResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(invalidateNodeInfos.getDynamicSimulationResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(invalidateNodeInfos.getDynamicSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsync(() -> dynamicMarginCalculationService.deleteResults(invalidateNodeInfos.getDynamicMarginCalculationResultUuids())), studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(invalidateNodeInfos.getStateEstimationResultUuids())), studyServerExecutionService.runAsync(() -> pccMinService.deletePccMinResults(invalidateNodeInfos.getPccMinResultUuids())) ); @@ -2327,6 +2376,7 @@ private void deleteNodesInfos(DeleteNodeInfos deleteNodeInfos) { studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(deleteNodeInfos.getVoltageInitResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(deleteNodeInfos.getDynamicSimulationResultUuids())), studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(deleteNodeInfos.getDynamicSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsync(() -> dynamicMarginCalculationService.deleteResults(deleteNodeInfos.getDynamicMarginCalculationResultUuids())), studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(deleteNodeInfos.getStateEstimationResultUuids())), studyServerExecutionService.runAsync(() -> pccMinService.deletePccMinResults(deleteNodeInfos.getPccMinResultUuids())) ); @@ -2915,7 +2965,7 @@ public List getDynamicSimulationModels(UUID studyUuid) { public void setDynamicSimulationParameters(UUID studyUuid, DynamicSimulationParametersInfos dsParameter, String userId) { updateDynamicSimulationParameters(studyUuid, DynamicSimulationService.toEntity(dsParameter != null ? dsParameter : DynamicSimulationService.getDefaultDynamicSimulationParameters(), objectMapper)); - // Dynamic security analysis depend on dynamic simulation => must invalidate + // Dynamic security analysis depends on dynamic simulation => must invalidate invalidateDynamicSecurityAnalysisStatusOnAllNodes(studyUuid); notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); @@ -3155,6 +3205,119 @@ private UUID handleDynamicSecurityAnalysisRequest(StudyEntity studyEntity, UUID // --- Dynamic Security Analysis service methods END --- // + // --- Dynamic Margin Calculation service methods BEGIN --- // + + public UUID getDynamicMarginCalculationParametersUuid(UUID studyUuid) { + StudyEntity studyEntity = getStudy(studyUuid); + return studyEntity.getDynamicMarginCalculationParametersUuid(); + } + + @Transactional + public String getDynamicMarginCalculationParameters(UUID studyUuid) { + StudyEntity studyEntity = getStudy(studyUuid); + return dynamicMarginCalculationService.getParameters( + dynamicMarginCalculationService.getDynamicMarginCalculationParametersUuidOrElseCreateDefault(studyEntity)); + } + + @Transactional + public boolean setDynamicMarginCalculationParameters(UUID studyUuid, String dsaParameter, String userId) { + StudyEntity studyEntity = getStudy(studyUuid); + boolean userProfileIssue = createOrUpdateDynamicMarginCalculationParameters(studyEntity, dsaParameter, userId); + invalidateDynamicMarginCalculationStatusOnAllNodes(studyUuid); + notificationService.emitStudyChanged(studyUuid, null, null, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); + notificationService.emitElementUpdated(studyUuid, userId); + notificationService.emitComputationParamsChanged(studyUuid, DYNAMIC_MARGIN_CALCULATION); + return userProfileIssue; + } + + public boolean createOrUpdateDynamicMarginCalculationParameters(StudyEntity studyEntity, String parameters, String userId) { + boolean userProfileIssue = false; + UUID existingDynamicMarginCalculationParametersUuid = studyEntity.getDynamicMarginCalculationParametersUuid(); + UserProfileInfos userProfileInfos = parameters == null ? userAdminService.getUserProfile(userId) : null; + if (parameters == null && userProfileInfos.getDynamicMarginCalculationParameterId() != null) { + // reset case, with existing profile, having default dynamic margin calculation params + try { + UUID dynamicMarginCalculationParametersFromProfileUuid = dynamicMarginCalculationService.duplicateParameters(userProfileInfos.getDynamicMarginCalculationParameterId()); + studyEntity.setDynamicMarginCalculationParametersUuid(dynamicMarginCalculationParametersFromProfileUuid); + removeDynamicMarginCalculationParameters(existingDynamicMarginCalculationParametersUuid); + return userProfileIssue; + } catch (Exception e) { + userProfileIssue = true; + LOGGER.error(String.format("Could not duplicate dynamic margin calculation parameters with id '%s' from user/profile '%s/%s'. Using default parameters", + userProfileInfos.getDynamicMarginCalculationParameterId(), userId, userProfileInfos.getName()), e); + // in case of duplication error (ex: wrong/dangling uuid in the profile), move on with default params below + } + } + + if (existingDynamicMarginCalculationParametersUuid == null) { + UUID newDynamicMarginCalculationParametersUuid = dynamicMarginCalculationService.createParameters(parameters); + studyEntity.setDynamicMarginCalculationParametersUuid(newDynamicMarginCalculationParametersUuid); + } else { + dynamicMarginCalculationService.updateParameters(existingDynamicMarginCalculationParametersUuid, parameters); + } + + return userProfileIssue; + } + + private void removeDynamicMarginCalculationParameters(@Nullable UUID dynamicMarginCalculationParametersUuid) { + if (dynamicMarginCalculationParametersUuid != null) { + try { + dynamicMarginCalculationService.deleteParameters(dynamicMarginCalculationParametersUuid); + } catch (Exception e) { + LOGGER.error("Could not remove dynamic margin calculation parameters with uuid:" + dynamicMarginCalculationParametersUuid, e); + } + } + } + + @Transactional + public UUID runDynamicMarginCalculation(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull UUID rootNetworkUuid, String userId, boolean debug) throws JsonProcessingException { + StudyEntity studyEntity = getStudy(studyUuid); + networkModificationTreeService.blockNode(rootNetworkUuid, nodeUuid); + + return handleDynamicMarginCalculationRequest(studyEntity, nodeUuid, rootNetworkUuid, debug, userId); + } + + private UUID handleDynamicMarginCalculationRequest(StudyEntity studyEntity, UUID nodeUuid, UUID rootNetworkUuid, boolean debug, String userId) throws JsonProcessingException { + + // pre-condition check + if (!rootNetworkNodeInfoService.isLoadflowConverged(nodeUuid, rootNetworkUuid)) { + throw new StudyException(NOT_ALLOWED, "Load flow must run successfully before running dynamic margin calculation"); + } + + // clean previous result if exist + UUID prevResultUuid = rootNetworkNodeInfoService.getComputationResultUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION); + if (prevResultUuid != null) { + dynamicMarginCalculationService.deleteResults(List.of(prevResultUuid)); + } + + // get dynamic simulation parameters entity + DynamicSimulationParametersInfos dynamicSimulationParametersInfos = getDynamicSimulationParameters(studyEntity); + String dynamicSimulationParametersInfosJson = objectMapper.writeValueAsString(dynamicSimulationParametersInfos); + + // get dynamic security analysis parameters uuid + UUID dynamicSecurityAnalysisParametersUuid = getDynamicSecurityAnalysisParametersUuid(studyEntity.getId()); + + // get dynamic margin calculation parameters uuid + UUID dynamicMarginCalculationParametersUuid = getDynamicMarginCalculationParametersUuid(studyEntity.getId()); + + UUID reportUuid = networkModificationTreeService.getComputationReports(nodeUuid, rootNetworkUuid).getOrDefault(DYNAMIC_MARGIN_CALCULATION.name(), UUID.randomUUID()); + networkModificationTreeService.updateComputationReportUuid(nodeUuid, rootNetworkUuid, DYNAMIC_MARGIN_CALCULATION, reportUuid); + + // launch dynamic margin calculation + UUID networkUuid = rootNetworkService.getNetworkUuid(rootNetworkUuid); + String variantId = networkModificationTreeService.getVariantId(nodeUuid, rootNetworkUuid); + UUID dynamicMarginCalculationResultUuid = dynamicMarginCalculationService.runDynamicMarginCalculation(studyEntity.getDynamicSimulationProvider(), + nodeUuid, rootNetworkUuid, networkUuid, variantId, reportUuid, dynamicSecurityAnalysisParametersUuid, dynamicMarginCalculationParametersUuid, dynamicSimulationParametersInfosJson, userId, debug); + + // update result uuid and notification + updateComputationResultUuid(nodeUuid, rootNetworkUuid, dynamicMarginCalculationResultUuid, DYNAMIC_MARGIN_CALCULATION); + notificationService.emitStudyChanged(studyEntity.getId(), nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); + + return dynamicMarginCalculationResultUuid; + } + + // --- Dynamic Margin Calculation service methods END --- // + public String getNetworkElementsIds(UUID nodeUuid, UUID rootNetworkUuid, List substationsIds, boolean inUpstreamBuiltParentNode, String equipmentType, List nominalVoltages) { UUID nodeUuidToSearchIn = getNodeUuidToSearchIn(nodeUuid, rootNetworkUuid, inUpstreamBuiltParentNode); return networkMapService.getElementsIds(rootNetworkService.getNetworkUuid(rootNetworkUuid), networkModificationTreeService.getVariantId(nodeUuidToSearchIn, rootNetworkUuid), @@ -3298,15 +3461,9 @@ private void emitAllComputationStatusChanged(UUID studyUuid, UUID nodeUuid, UUID if (!InvalidateNodeTreeParameters.ComputationsInvalidationMode.isPreserveLoadFlowResults(computationsInvalidationMode)) { notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); } - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS); - notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, NotificationService.UPDATE_TYPE_PCC_MIN_STATUS); + ALL_COMPUTATION_STATUS.stream() + .filter(computationStatus -> computationStatus != NotificationService.UPDATE_TYPE_LOADFLOW_STATUS) + .forEach(computationStatus -> notificationService.emitStudyChanged(studyUuid, nodeUuid, rootNetworkUuid, computationStatus)); } @Transactional(readOnly = true) diff --git a/src/main/java/org/gridsuite/study/server/service/SupervisionService.java b/src/main/java/org/gridsuite/study/server/service/SupervisionService.java index b2e814dd21..2871a5a5f6 100644 --- a/src/main/java/org/gridsuite/study/server/service/SupervisionService.java +++ b/src/main/java/org/gridsuite/study/server/service/SupervisionService.java @@ -17,6 +17,7 @@ import org.gridsuite.study.server.repository.StudyRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; +import org.gridsuite.study.server.service.dynamicmargincalculation.DynamicMarginCalculationService; import org.gridsuite.study.server.service.dynamicsecurityanalysis.DynamicSecurityAnalysisService; import org.gridsuite.study.server.service.dynamicsimulation.DynamicSimulationService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; @@ -59,6 +60,8 @@ public class SupervisionService { private final DynamicSecurityAnalysisService dynamicSecurityAnalysisService; + private final DynamicMarginCalculationService dynamicMarginCalculationService; + private final SecurityAnalysisService securityAnalysisService; private final SensitivityAnalysisService sensitivityAnalysisService; @@ -88,6 +91,7 @@ public SupervisionService(StudyService studyService, LoadFlowService loadFlowService, DynamicSimulationService dynamicSimulationService, DynamicSecurityAnalysisService dynamicSecurityAnalysisService, + DynamicMarginCalculationService dynamicMarginCalculationService, SecurityAnalysisService securityAnalysisService, SensitivityAnalysisService sensitivityAnalysisService, ShortCircuitService shortCircuitService, @@ -106,6 +110,7 @@ public SupervisionService(StudyService studyService, this.loadFlowService = loadFlowService; this.dynamicSimulationService = dynamicSimulationService; this.dynamicSecurityAnalysisService = dynamicSecurityAnalysisService; + this.dynamicMarginCalculationService = dynamicMarginCalculationService; this.securityAnalysisService = securityAnalysisService; this.sensitivityAnalysisService = sensitivityAnalysisService; this.shortCircuitService = shortCircuitService; @@ -127,6 +132,8 @@ public Integer deleteComputationResults(ComputationType computationType, boolean dryRun ? dynamicSimulationService.getResultsCount() : deleteDynamicSimulationResults(); case DYNAMIC_SECURITY_ANALYSIS -> dryRun ? dynamicSecurityAnalysisService.getResultsCount() : deleteDynamicSecurityAnalysisResults(); + case DYNAMIC_MARGIN_CALCULATION -> + dryRun ? dynamicMarginCalculationService.getResultsCount() : deleteDynamicMarginCalculationResults(); case SECURITY_ANALYSIS -> dryRun ? securityAnalysisService.getSecurityAnalysisResultsCount() : deleteSecurityAnalysisResults(); case SENSITIVITY_ANALYSIS -> @@ -218,6 +225,16 @@ private Integer deleteDynamicSecurityAnalysisResults() { return rootNetworkNodeStatusEntities.size(); } + private Integer deleteDynamicMarginCalculationResults() { + AtomicReference startTime = new AtomicReference<>(); + startTime.set(System.nanoTime()); + List rootNetworkNodeStatusEntities = rootNetworkNodeInfoRepository.findAllByDynamicMarginCalculationResultUuidNotNull(); + rootNetworkNodeStatusEntities.forEach(rootNetworkNodeStatus -> rootNetworkNodeStatus.setDynamicMarginCalculationResultUuid(null)); + dynamicMarginCalculationService.deleteAllResults(); + LOGGER.trace(DELETION_LOG_MESSAGE, ComputationType.DYNAMIC_MARGIN_CALCULATION, TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); + return rootNetworkNodeStatusEntities.size(); + } + private Integer deleteSecurityAnalysisResults() { AtomicReference startTime = new AtomicReference<>(); startTime.set(System.nanoTime()); diff --git a/src/main/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClient.java b/src/main/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClient.java new file mode 100644 index 0000000000..fef9136cbc --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/service/client/dynamicmargincalculation/DynamicMarginCalculationClient.java @@ -0,0 +1,276 @@ +/* + * 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.study.server.service.client.dynamicmargincalculation; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.gridsuite.study.server.RemoteServicesProperties; +import org.gridsuite.study.server.dto.ReportInfos; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; +import org.gridsuite.study.server.service.StudyService; +import org.gridsuite.study.server.service.client.AbstractRestClient; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import static org.gridsuite.study.server.StudyConstants.*; +import static org.gridsuite.study.server.notification.NotificationService.HEADER_USER_ID; +import static org.gridsuite.study.server.service.client.util.UrlUtil.buildEndPointUrl; + +/** + * @author Thang PHAM + */ +@Service +public class DynamicMarginCalculationClient extends AbstractRestClient { + public static final String API_VERSION = DYNAMIC_MARGIN_CALCULATION_API_VERSION; + public static final String DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER = "parameters"; + public static final String DYNAMIC_MARGIN_CALCULATION_END_POINT_RUN = "networks"; + public static final String DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT = "results"; + + protected DynamicMarginCalculationClient(RemoteServicesProperties remoteServicesProperties, + RestTemplate restTemplate) { + super(remoteServicesProperties.getServiceUri("dynamic-margin-calculation-server"), restTemplate); + } + + private String getParametersWithUuidUrl(UUID parametersUuid) { + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + return UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/{uuid}") + .buildAndExpand(parametersUuid) + .toUriString(); + } + + // --- Related parameters methods --- // + + public String getDefaultProvider() { + String rootBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, null); + + String url = UriComponentsBuilder + .fromUriString(rootBaseUrl + "/default-provider") + .toUriString(); + + return getRestTemplate().getForObject(url, String.class); + } + + public String getProvider(@NonNull UUID parametersUuid) { + Objects.requireNonNull(parametersUuid); + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/{uuid}/provider") + .buildAndExpand(parametersUuid) + .toUriString(); + + return getRestTemplate().getForObject(url, String.class); + } + + public void updateProvider(@NonNull UUID parametersUuid, @NonNull String provider) { + Objects.requireNonNull(parametersUuid); + Objects.requireNonNull(provider); + + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/{uuid}/provider") + .buildAndExpand(parametersUuid) + .toUriString(); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity httpEntity = new HttpEntity<>(provider, headers); + + // call dynamic-margin-calculation REST API + getRestTemplate().put(url, httpEntity); + } + + public String getParameters(@NonNull UUID parametersUuid) { + Objects.requireNonNull(parametersUuid); + + String url = getParametersWithUuidUrl(parametersUuid); + + return getRestTemplate().getForObject(url, String.class); + } + + public UUID createParameters(@NonNull String parametersInfos) { + Objects.requireNonNull(parametersInfos); + + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl) + .buildAndExpand() + .toUriString(); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity httpEntity = new HttpEntity<>(parametersInfos, headers); + + return getRestTemplate().postForObject(url, httpEntity, UUID.class); + } + + public void updateParameters(@NonNull UUID parametersUuid, @NonNull String parametersInfos) { + Objects.requireNonNull(parametersUuid); + Objects.requireNonNull(parametersInfos); + + String url = getParametersWithUuidUrl(parametersUuid); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity httpEntity = new HttpEntity<>(parametersInfos, headers); + + getRestTemplate().put(url, httpEntity); + } + + public UUID duplicateParameters(@NonNull UUID sourceParametersUuid) { + Objects.requireNonNull(sourceParametersUuid); + + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl) + .queryParam("duplicateFrom", sourceParametersUuid) + .buildAndExpand() + .toUriString(); + + return getRestTemplate().postForObject(url, null, UUID.class); + } + + public void deleteParameters(@NonNull UUID parametersUuid) { + Objects.requireNonNull(parametersUuid); + + String url = getParametersWithUuidUrl(parametersUuid); + + // call dynamic-margin-calculation REST API + getRestTemplate().delete(url); + } + + public UUID createDefaultParameters() { + String parametersBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_PARAMETER); + + String url = UriComponentsBuilder + .fromUriString(parametersBaseUrl + "/default") + .buildAndExpand() + .toUriString(); + + return getRestTemplate().postForObject(url, null, UUID.class); + } + + // --- Related run computation methods --- // + + public UUID run(String provider, @NonNull String receiver, @NonNull UUID networkUuid, String variantId, + @NonNull ReportInfos reportInfos, @NonNull UUID dynamicSecurityAnalysisParametersUuid, + @NonNull UUID parametersUuid, @NonNull String dynamicSimulationParametersJson, String userId, boolean debug) { + Objects.requireNonNull(receiver); + Objects.requireNonNull(networkUuid); + Objects.requireNonNull(reportInfos); + Objects.requireNonNull(dynamicSecurityAnalysisParametersUuid); + Objects.requireNonNull(parametersUuid); + + String runBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RUN); + + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(runBaseUrl + "/{networkUuid}/run"); + if (StringUtils.isNotBlank(variantId)) { + uriComponentsBuilder.queryParam(QUERY_PARAM_VARIANT_ID, variantId); + } + if (StringUtils.isNotBlank(provider)) { + uriComponentsBuilder.queryParam("provider", provider); + } + if (debug) { + uriComponentsBuilder.queryParam(QUERY_PARAM_DEBUG, true); + } + uriComponentsBuilder + .queryParam("dynamicSecurityAnalysisParametersUuid", dynamicSecurityAnalysisParametersUuid) + .queryParam("parametersUuid", parametersUuid) + .queryParam(QUERY_PARAM_RECEIVER, receiver) + .queryParam(QUERY_PARAM_REPORT_UUID, reportInfos.reportUuid()) + .queryParam(QUERY_PARAM_REPORTER_ID, reportInfos.nodeUuid()) + .queryParam(QUERY_PARAM_REPORT_TYPE, StudyService.ReportType.DYNAMIC_SECURITY_ANALYSIS.reportKey); + String url = uriComponentsBuilder + .buildAndExpand(networkUuid) + .toUriString(); + + HttpHeaders headers = new HttpHeaders(); + headers.set(HEADER_USER_ID, userId); + headers.setContentType(MediaType.APPLICATION_JSON); + + // call dynamic-margin-calculation REST API + HttpEntity httpEntity = new HttpEntity<>(dynamicSimulationParametersJson, headers); + + return getRestTemplate().postForObject(url, httpEntity, UUID.class); + } + + // --- Related result methods --- // + + public DynamicMarginCalculationStatus getStatus(@NonNull UUID resultUuid) { + Objects.requireNonNull(resultUuid); + + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl + "/{resultUuid}/status") + .buildAndExpand(resultUuid) + .toUriString(); + + // call dynamic-margin-calculation REST API + return getRestTemplate().getForObject(url, DynamicMarginCalculationStatus.class); + } + + public void invalidateStatus(@NonNull List resultUuids) { + if (CollectionUtils.isEmpty(resultUuids)) { + return; + } + + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl + "/invalidate-status") + .queryParam("resultUuid", resultUuids) + .build() + .toUriString(); + + getRestTemplate().exchange(url, HttpMethod.PUT, null, new ParameterizedTypeReference>() { }); + } + + public void deleteResults(List resultUuids) { + if (CollectionUtils.isEmpty(resultUuids)) { + return; + } + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl) + .queryParam(QUERY_PARAM_RESULTS_UUIDS, resultUuids) + .build() + .toUriString(); + // call dynamic-margin-calculation REST API + getRestTemplate().delete(url); + } + + public Integer getResultsCount() { + String resultBaseUrl = buildEndPointUrl(getBaseUri(), DYNAMIC_MARGIN_CALCULATION_API_VERSION, DYNAMIC_MARGIN_CALCULATION_END_POINT_RESULT); + String url = UriComponentsBuilder + .fromUriString(resultBaseUrl) + .toUriString(); + + // call dynamic-margin-calculation REST API + return getRestTemplate().getForObject(url, Integer.class); + } +} diff --git a/src/main/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationService.java b/src/main/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationService.java new file mode 100644 index 0000000000..4cdeb27095 --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/service/dynamicmargincalculation/DynamicMarginCalculationService.java @@ -0,0 +1,133 @@ +/* + * 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.study.server.service.dynamicmargincalculation; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.collections4.CollectionUtils; +import org.gridsuite.study.server.dto.NodeReceiver; +import org.gridsuite.study.server.dto.ReportInfos; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; +import org.gridsuite.study.server.error.StudyException; +import org.gridsuite.study.server.repository.StudyEntity; +import org.gridsuite.study.server.service.client.dynamicmargincalculation.DynamicMarginCalculationClient; +import org.springframework.stereotype.Service; + +import java.io.UncheckedIOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.UUID; + +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.COMPUTATION_RUNNING; + +/** + * @author Thang PHAM + */ +@Service +public class DynamicMarginCalculationService { + + private final ObjectMapper objectMapper; + + private final DynamicMarginCalculationClient dynamicMarginCalculationClient; + + public DynamicMarginCalculationService(ObjectMapper objectMapper, + DynamicMarginCalculationClient dynamicMarginCalculationClient) { + this.objectMapper = objectMapper; + this.dynamicMarginCalculationClient = dynamicMarginCalculationClient; + } + + public String getParameters(UUID parametersUuid) { + return dynamicMarginCalculationClient.getParameters(parametersUuid); + } + + public UUID createParameters(String parameters) { + return dynamicMarginCalculationClient.createParameters(parameters); + } + + public UUID createDefaultParameters() { + return dynamicMarginCalculationClient.createDefaultParameters(); + } + + public void updateParameters(UUID parametersUuid, String parametersInfos) { + dynamicMarginCalculationClient.updateParameters(parametersUuid, parametersInfos); + } + + public UUID duplicateParameters(UUID sourceParameterId) { + return dynamicMarginCalculationClient.duplicateParameters(sourceParameterId); + } + + public void deleteParameters(UUID parametersUuid) { + dynamicMarginCalculationClient.deleteParameters(parametersUuid); + } + + public UUID runDynamicMarginCalculation(String provider, UUID nodeUuid, UUID rootNetworkUuid, UUID networkUuid, + String variantId, UUID reportUuid, UUID dynamicSecurityAnalysisParametersUuid, UUID parametersUuid, String dynamicSimulationParametersJson, String userId, boolean debug) { + + // create receiver for getting back the notification in rabbitmq + String receiver; + + try { + receiver = URLEncoder.encode(objectMapper.writeValueAsString(new NodeReceiver(nodeUuid, rootNetworkUuid)), + StandardCharsets.UTF_8); + } catch (JsonProcessingException e) { + throw new UncheckedIOException(e); + } + + return dynamicMarginCalculationClient.run(provider, receiver, networkUuid, variantId, new ReportInfos(reportUuid, nodeUuid), dynamicSecurityAnalysisParametersUuid, parametersUuid, dynamicSimulationParametersJson, userId, debug); + } + + public DynamicMarginCalculationStatus getStatus(UUID resultUuid) { + return resultUuid == null ? null : dynamicMarginCalculationClient.getStatus(resultUuid); + } + + public void invalidateStatus(List resultUuids) { + if (CollectionUtils.isNotEmpty(resultUuids)) { + dynamicMarginCalculationClient.invalidateStatus(resultUuids); + } + } + + public void deleteResults(List resultUuids) { + dynamicMarginCalculationClient.deleteResults(resultUuids); + } + + public void deleteAllResults() { + deleteResults(null); + } + + public Integer getResultsCount() { + return dynamicMarginCalculationClient.getResultsCount(); + } + + public void assertDynamicMarginCalculationNotRunning(UUID resultUuid) { + DynamicMarginCalculationStatus status = getStatus(resultUuid); + if (DynamicMarginCalculationStatus.RUNNING == status) { + throw new StudyException(COMPUTATION_RUNNING); + } + } + + public UUID getDynamicMarginCalculationParametersUuidOrElseCreateDefault(StudyEntity studyEntity) { + if (studyEntity.getDynamicMarginCalculationParametersUuid() == null) { + // not supposed to happen because we create it as the study creation + studyEntity.setDynamicMarginCalculationParametersUuid(dynamicMarginCalculationClient.createDefaultParameters()); + } + return studyEntity.getDynamicMarginCalculationParametersUuid(); + } + + public void updateProvider(UUID parametersUuid, String provider) { + dynamicMarginCalculationClient.updateProvider(parametersUuid, provider); + } + + public String getDefaultProvider() { + return dynamicMarginCalculationClient.getDefaultProvider(); + } + + public String getProvider(UUID parametersUuid) { + return dynamicMarginCalculationClient.getProvider(parametersUuid); + } +} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 237f8990cb..a38d05375d 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -61,6 +61,9 @@ gridsuite: - name: dynamic-security-analysis-server base-uri: http://localhost:5040 + - + name: dynamic-margin-calculation-server + base-uri: http://localhost:5041 - name: timeseries-server base-uri: http://localhost:5037 diff --git a/src/main/resources/config/application.yaml b/src/main/resources/config/application.yaml index fd28d3a7bc..2e12cf7541 100644 --- a/src/main/resources/config/application.yaml +++ b/src/main/resources/config/application.yaml @@ -8,6 +8,7 @@ spring: definition: "consumeSaResult;consumeSaStopped;consumeSaFailed;consumeSaCancelFailed;\ consumeDsDebug;consumeDsResult;consumeDsStopped;consumeDsFailed;consumeDsCancelFailed;\ consumeDsaDebug;consumeDsaResult;consumeDsaStopped;consumeDsaFailed;consumeDsaCancelFailed;\ + consumeDmcDebug;consumeDmcResult;consumeDmcStopped;consumeDmcFailed;consumeDmcCancelFailed;\ consumeBuildResult;consumeBuildStopped;consumeBuildFailed;\ consumeCaseImportSucceeded;consumeCaseImportFailed;\ consumeSensitivityAnalysisResult;consumeSensitivityAnalysisStopped;consumeSensitivityAnalysisFailed;consumeSensitivityAnalysisCancelFailed;\ @@ -65,6 +66,21 @@ spring: consumeDsaFailed-in-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}dsa.run.dlx group: dlq + consumeDmcDebug-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.debug + group: studyDsaDebugGroup + consumeDmcResult-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.result + group: studyDsaResultGroup + consumeDmcStopped-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.stopped + group: studyDsaStoppedGroup + consumeDmcCancelFailed-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.cancelfailed + group: studyDsaCancelFailedGroup + consumeDmcFailed-in-0: + destination: ${powsybl-ws.rabbitmq.destination.prefix:}dmc.run.dlx + group: dlq consumeBuildResult-in-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}build.result group: studyBuildResultGroup @@ -207,6 +223,9 @@ gridsuite: - name: dynamic-security-analysis-server base-uri: http://dynamic-security-analysis-server/ + - + name: dynamic-margin-calculation-server + base-uri: http://dynamic-margin-calculation-server/ - name: timeseries-server base-uri: http://timeseries-server/ diff --git a/src/main/resources/db/changelog/changesets/changelog_20260106T162321Z.xml b/src/main/resources/db/changelog/changesets/changelog_20260106T162321Z.xml new file mode 100644 index 0000000000..a5d5ac3652 --- /dev/null +++ b/src/main/resources/db/changelog/changesets/changelog_20260106T162321Z.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index e61c2d7626..e8fd514378 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -356,3 +356,6 @@ databaseChangeLog: - include: file: changesets/changelog_20251113T131808Z.xml relativeToChangelogFile: true + - include: + file: changesets/changelog_20260106T162321Z.xml + relativeToChangelogFile: true diff --git a/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java b/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java index 19e2b067e4..9fa46dd90e 100644 --- a/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java +++ b/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java @@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.gridsuite.study.server.dto.ComputationType.LOAD_FLOW; +import static org.gridsuite.study.server.notification.NotificationService.ALL_COMPUTATION_STATUS; import static org.gridsuite.study.server.utils.TestUtils.synchronizeStudyServerExecutionService; import static org.mockito.Mockito.*; @@ -171,7 +172,8 @@ private void testRerunLoadFlowSecurityNode(boolean withRatioTapChangers) { // node invalidation verify(networkModificationTreeService, times(1)).invalidateNodeTree(nodeUuid, rootNetworkUuid, expectedInvalidationParameters); verify(networkModificationService, times(1)).deleteIndexedModifications(invalidateNodeInfos.getGroupUuids(), networkUuid); - verify(notificationService, times(9)).emitStudyChanged(eq(studyUuid), eq(nodeUuid), eq(rootNetworkUuid), anyString()); + verify(notificationService, times(ALL_COMPUTATION_STATUS.size() - 1 /* except loadflow which is tested in PRESERVE_LOAD_FLOW_RESULTS mode */)) + .emitStudyChanged(eq(studyUuid), eq(nodeUuid), eq(rootNetworkUuid), anyString()); // node build ArgumentCaptor rerunLoadFlowWorkflowInfosArgumentCaptor = ArgumentCaptor.forClass(RerunLoadFlowInfos.class); diff --git a/src/test/java/org/gridsuite/study/server/LoadFlowTest.java b/src/test/java/org/gridsuite/study/server/LoadFlowTest.java index 5f12d496ea..7b12d54bd5 100644 --- a/src/test/java/org/gridsuite/study/server/LoadFlowTest.java +++ b/src/test/java/org/gridsuite/study/server/LoadFlowTest.java @@ -361,8 +361,8 @@ private void consumeLoadFlowResult(UUID studyUuid, UUID rootNetworkUuid, Network String resultUuidJson = objectMapper.writeValueAsString(new NodeReceiver(nodeUuid, rootNetworkUuid)); MessageHeaders messageHeaders = new MessageHeaders(Map.of("resultUuid", LOADFLOW_RESULT_UUID, "withRatioTapChangers", false, HEADER_RECEIVER, resultUuidJson)); consumerService.consumeLoadFlowResult().accept(MessageBuilder.createMessage("", messageHeaders)); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_LOADFLOW_RESULT); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_LOADFLOW_RESULT); assertNodeBlocked(nodeUuid, rootNetworkUuid, false); } @@ -413,10 +413,10 @@ private void testLoadFlow(final MockWebServer server, UUID studyNameUserIdUuid, // running loadflow invalidate node children and their computations if (modificationNode.isSecurityNode()) { - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); } - checkUpdateModelStatusMessagesReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); + checkUpdateStatusMessageReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); List expectedRequestsPatterns = new ArrayList<>(); expectedRequestsPatterns.add("/v1/networks/" + NETWORK_UUID_STRING + "/run-and-save\\?withRatioTapChangers=.*&receiver=.*&reportUuid=.*&reporterId=.*&variantId=" + VARIANT_ID_2); @@ -448,7 +448,7 @@ private void testLoadFlow(final MockWebServer server, UUID studyNameUserIdUuid, .header(HEADER_USER_ID, "userId")) .andExpect(status().isOk()); - checkUpdateModelStatusMessagesReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS, NotificationService.UPDATE_TYPE_LOADFLOW_RESULT); + checkUpdateStatusMessageReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS, NotificationService.UPDATE_TYPE_LOADFLOW_RESULT); assertTrue(TestUtils.getRequestsDone(1, server).stream().anyMatch(r -> r.matches("/v1/results/" + LOADFLOW_RESULT_UUID + "/stop\\?receiver=.*nodeUuid.*"))); } @@ -461,8 +461,8 @@ private void testLoadFlowFailed(final MockWebServer server, UUID studyNameUserId .header("userId", "userId")) .andExpect(status().isOk()); - checkUpdateModelStatusMessagesReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_FAILED); - checkUpdateModelStatusMessagesReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); + checkUpdateStatusMessageReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_FAILED); + checkUpdateStatusMessageReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); assertRequestsDone(server, List.of("/v1/parameters/" + LOADFLOW_PARAMETERS_UUID + "/provider", "/v1/networks/" + NETWORK_UUID_STRING + "/run-and-save\\?withRatioTapChangers=.*&receiver=.*&reportUuid=.*&reporterId=.*&variantId=" + VARIANT_ID)); } @@ -491,9 +491,9 @@ void testGetLimitViolations(final MockWebServer server) throws Exception { .andReturn(); // running loadflow (with security node) invalidate node children and their computations - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); - checkUpdateModelStatusMessagesReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); + checkUpdateStatusMessageReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); assertRequestsDone(server, List.of("/v1/networks/" + NETWORK_UUID_STRING + "/run-and-save\\?withRatioTapChangers=.*&receiver=.*&reportUuid=.*&reporterId=.*&variantId=" + VARIANT_ID_2)); consumeLoadFlowResult(studyNameUserIdUuid, firstRootNetworkUuid, modificationNode1); @@ -547,9 +547,9 @@ void testInvalidateStatus(final MockWebServer server) throws Exception { .andReturn(); // running loadflow (with security node) invalidate children and their computations - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); - checkUpdateModelStatusMessagesReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); + checkUpdateStatusMessageReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); assertRequestsDone(server, List.of("/v1/networks/" + NETWORK_UUID_STRING + "/run-and-save\\?withRatioTapChangers=.*&receiver=.*&reportUuid=.*&reporterId=.*&variantId=" + VARIANT_ID_2)); consumeLoadFlowResult(studyNameUserIdUuid, firstRootNetworkUuid, modificationNode1); @@ -584,9 +584,9 @@ void testDeleteLoadFlowResults(final MockWebServer server) throws Exception { .andExpect(status().isOk()); // running loadflow ((with security node)) invalidate node children and their computations - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode3Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode3Uuid); - checkUpdateModelStatusMessagesReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); + checkUpdateStatusMessageReceived(studyNameUserIdUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); assertRequestsDone(server, List.of("/v1/networks/" + NETWORK_UUID_STRING + "/run-and-save\\?withRatioTapChangers=.*&receiver=.*&reportUuid=.*&reporterId=.*&variantId=" + VARIANT_ID_2)); consumeLoadFlowResult(studyNameUserIdUuid, firstRootNetworkUuid, modificationNode3); @@ -627,7 +627,7 @@ void testResetUuidResultWhenLFFailed() throws Exception { assertEquals(NotificationService.UPDATE_TYPE_LOADFLOW_FAILED, updateType); } - private void checkUpdateModelStatusMessagesReceived(UUID studyUuid, String updateTypeToCheck, String otherUpdateTypeToCheck) { + private void checkUpdateStatusMessageReceived(UUID studyUuid, String updateTypeToCheck, String otherUpdateTypeToCheck) { Message loadFlowStatusMessage = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); assertEquals(studyUuid, loadFlowStatusMessage.getHeaders().get(NotificationService.HEADER_STUDY_UUID)); String updateType = (String) loadFlowStatusMessage.getHeaders().get(HEADER_UPDATE_TYPE); @@ -638,8 +638,8 @@ private void checkUpdateModelStatusMessagesReceived(UUID studyUuid, String updat } } - private void checkUpdateModelStatusMessagesReceived(UUID studyUuid, String updateTypeToCheck) { - checkUpdateModelStatusMessagesReceived(studyUuid, updateTypeToCheck, null); + private void checkUpdateStatusMessageReceived(UUID studyUuid, String updateTypeToCheck) { + checkUpdateStatusMessageReceived(studyUuid, updateTypeToCheck, null); } private void testResultCount(final MockWebServer server) throws Exception { @@ -665,7 +665,7 @@ private void testDeleteResults(UUID studyUuid, int expectedInitialResultCount, f assertTrue(requests.stream().anyMatch(r -> r.matches("/v1/reports"))); assertEquals(0, rootNetworkNodeInfoRepository.findAllByLoadFlowResultUuidNotNull().size()); - checkUpdateModelsStatusMessagesReceived(studyUuid); + checkUpdateStatusMessagesReceived(studyUuid); assertEquals(BuildStatus.NOT_BUILT, rootNetworkNodeInfoRepository.findById(rootNetworkNodeInfoEntity.getId()).get().getNodeBuildStatus().getLocalBuildStatus()); } @@ -713,6 +713,8 @@ private void createOrUpdateParametersAndDoChecks(UUID studyNameUserIdUuid, Strin assertEquals(NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS, message.getHeaders().get(NotificationService.HEADER_UPDATE_TYPE)); message = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); assertEquals(NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS, message.getHeaders().get(NotificationService.HEADER_UPDATE_TYPE)); + message = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); + assertEquals(NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS, message.getHeaders().get(NotificationService.HEADER_UPDATE_TYPE)); message = output.receive(TIMEOUT, ELEMENT_UPDATE_DESTINATION); assertEquals(studyNameUserIdUuid, message.getHeaders().get(NotificationService.HEADER_ELEMENT_UUID)); @@ -939,14 +941,15 @@ void testInvalidateNodesAfterLoadflow(final MockWebServer server) throws Excepti // node2 and node3 will be invalidated with their children, but the order in which way they are invalidated is not deterministic // this is why we don't check node uuid here for those two calls - checkUpdateModelsStatusMessagesReceived(studyUuid); + checkUpdateStatusMessagesReceived(studyUuid); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, NotificationService.UPDATE_TYPE_COMPUTATION_PARAMETERS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_DYNAMIC_MARGIN_CALCULATION_STATUS); + checkUpdateStatusMessageReceived(studyUuid, NotificationService.UPDATE_TYPE_COMPUTATION_PARAMETERS); var requests = TestUtils.getRequestsDone(5, server); assertTrue(requests.stream().anyMatch(r -> r.equals("/v1/users/" + NO_PROFILE_USER_ID + "/profile"))); @@ -1055,7 +1058,7 @@ private NetworkModificationNode createNetworkModificationNode(UUID studyUuid, UU return modificationNode; } - private void checkUpdateModelStatusMessagesReceived(UUID studyUuid, UUID nodeUuid, String updateType) { + private void checkUpdateStatusMessageReceived(UUID studyUuid, UUID nodeUuid, String updateType) { // assert that the broker message has been sent for updating model status Message messageStatus = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); assertEquals("", new String(messageStatus.getPayload())); @@ -1067,26 +1070,17 @@ private void checkUpdateModelStatusMessagesReceived(UUID studyUuid, UUID nodeUui assertEquals(updateType, headersStatus.get(NotificationService.HEADER_UPDATE_TYPE)); } - private void checkUpdateModelsStatusMessagesReceived(UUID studyUuid, UUID nodeUuid) { - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, UPDATE_TYPE_PCC_MIN_STATUS); + private void checkUpdateStatusMessagesReceived(UUID studyUuid, UUID nodeUuid) { + ALL_COMPUTATION_STATUS.forEach(computationStatus -> checkUpdateStatusMessageReceived(studyUuid, nodeUuid, computationStatus)); } - private void checkUpdateModelsStatusMessagesReceived(UUID studyUuid) { + private void checkUpdateStatusMessagesReceived(UUID studyUuid) { Message messageStatus = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); MessageHeaders headersStatus = messageStatus.getHeaders(); assertEquals(studyUuid, headersStatus.get(NotificationService.HEADER_STUDY_UUID)); assertEquals(NODE_BUILD_STATUS_UPDATED, headersStatus.get(NotificationService.HEADER_UPDATE_TYPE)); List nodesToInvalidate = (List) headersStatus.get(NotificationService.HEADER_NODES); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodesToInvalidate.get(0)); + checkUpdateStatusMessagesReceived(studyUuid, nodesToInvalidate.get(0)); } @AfterEach diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java index 44df470fbf..c5eb3c5082 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java @@ -31,6 +31,7 @@ import okhttp3.Headers; import okhttp3.HttpUrl; import org.gridsuite.study.server.dto.*; +import org.gridsuite.study.server.dto.dynamicmargincalculation.DynamicMarginCalculationStatus; import org.gridsuite.study.server.dto.dynamicsecurityanalysis.DynamicSecurityAnalysisStatus; import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationStatus; import org.gridsuite.study.server.dto.impacts.SimpleElementImpact.SimpleImpactType; @@ -46,10 +47,14 @@ import org.gridsuite.study.server.repository.StudyRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; import org.gridsuite.study.server.service.*; +import org.gridsuite.study.server.service.client.dynamicmargincalculation.DynamicMarginCalculationClient; import org.gridsuite.study.server.service.client.dynamicsecurityanalysis.DynamicSecurityAnalysisClient; import org.gridsuite.study.server.service.client.dynamicsimulation.DynamicSimulationClient; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; -import org.gridsuite.study.server.utils.*; +import org.gridsuite.study.server.utils.MatcherJson; +import org.gridsuite.study.server.utils.RequestWithBody; +import org.gridsuite.study.server.utils.SendInput; +import org.gridsuite.study.server.utils.TestUtils; import org.gridsuite.study.server.utils.elasticsearch.DisableElasticsearch; import org.gridsuite.study.server.utils.wiremock.WireMockStubs; import org.gridsuite.study.server.utils.wiremock.WireMockUtils; @@ -79,15 +84,18 @@ import org.springframework.test.web.servlet.MvcResult; import java.util.*; +import java.util.stream.Collectors; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*; import static org.gridsuite.study.server.StudyConstants.HEADER_ERROR_MESSAGE; import static org.gridsuite.study.server.StudyConstants.QUERY_PARAM_RECEIVER; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.MAX_NODE_BUILDS_EXCEEDED; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NOT_FOUND; import static org.gridsuite.study.server.utils.ImpactUtils.createModificationResultWithElementImpact; import static org.gridsuite.study.server.utils.JsonUtils.getModificationContextJsonString; import static org.gridsuite.study.server.utils.MatcherCreatedStudyBasicInfos.createMatcherCreatedStudyBasicInfos; import static org.gridsuite.study.server.utils.SendInput.POST_ACTION_SEND_INPUT; +import static org.gridsuite.study.server.utils.TestUtils.checkUpdateStatusMessagesReceived; import static org.gridsuite.study.server.utils.TestUtils.synchronizeStudyServerExecutionService; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -128,6 +136,7 @@ class NetworkModificationTest { private static final UUID LOADFLOW_RESULT_UUID = UUID.randomUUID(); private static final UUID DYNAMIC_SIMULATION_RESULT_UUID = UUID.randomUUID(); private static final UUID DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID = UUID.randomUUID(); + private static final UUID DYNAMIC_MARGIN_CALCULATION_RESULT_UUID = UUID.randomUUID(); private static final String SECURITY_ANALYSIS_RESULT_UUID = "f3a85c9b-9594-4e55-8ec7-07ea965d24eb"; private static final String SECURITY_ANALYSIS_STATUS_JSON = "\"CONVERGED\""; @@ -228,6 +237,9 @@ class NetworkModificationTest { @MockitoSpyBean DynamicSecurityAnalysisClient dynamicSecurityAnalysisClient; + @MockitoSpyBean + DynamicMarginCalculationClient dynamicMarginCalculationClient; + @MockitoSpyBean private RootNetworkNodeInfoRepository rootNetworkNodeInfoRepository; @@ -292,6 +304,7 @@ void setup(final MockWebServer server) { doReturn(baseUrl).when(dynamicSimulationClient).getBaseUri(); doReturn(baseUrl).when(dynamicSecurityAnalysisClient).getBaseUri(); + doReturn(baseUrl).when(dynamicMarginCalculationClient).getBaseUri(); String baseUrlWireMock = wireMockServer.baseUrl(); networkModificationService.setNetworkModificationServerBaseUri(baseUrlWireMock); @@ -361,6 +374,15 @@ public MockResponse dispatch(RecordedRequest request) { return new MockResponse(200, Headers.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE), objectMapper.writeValueAsString(DynamicSecurityAnalysisStatus.SUCCEED)); } return new MockResponse(500); + } else if (("/v1/results/invalidate-status?resultUuid=" + DYNAMIC_MARGIN_CALCULATION_RESULT_UUID).equals(path)) { + return new MockResponse(200); + } else if (("/v1/results/" + DYNAMIC_MARGIN_CALCULATION_RESULT_UUID + "/status").equals(path)) { + return new MockResponse(200, Headers.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE), objectMapper.writeValueAsString(DynamicMarginCalculationStatus.SUCCEED)); + } else if (("/v1/results?resultsUuids=" + DYNAMIC_MARGIN_CALCULATION_RESULT_UUID).equals(path)) { + if (request.getMethod().equals("DELETE")) { + return new MockResponse(200, Headers.of(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE), objectMapper.writeValueAsString(DynamicMarginCalculationStatus.SUCCEED)); + } + return new MockResponse(500); } else if (("/v1/results/invalidate-status?resultUuid=" + SENSITIVITY_ANALYSIS_RESULT_UUID).equals(path)) { return new MockResponse(200); } else if (("/v1/results/" + SENSITIVITY_ANALYSIS_RESULT_UUID + "/status").equals(path)) { @@ -632,7 +654,7 @@ void testLocalBuildValue() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNodeUuid)); @@ -650,7 +672,7 @@ void testLocalBuildValue() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNode2Uuid)); @@ -704,7 +726,7 @@ void testNetworkModificationSwitch(final MockWebServer server) throws Exception .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -725,7 +747,7 @@ void testNetworkModificationSwitch(final MockWebServer server) throws Exception .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -752,7 +774,7 @@ void testNetworkModificationSwitch(final MockWebServer server) throws Exception Set substationsSet = ImmutableSet.of("s3", "s1", "s2"); NetworkImpactsInfos expectedPayload = NetworkImpactsInfos.builder().impactedSubstationsIds(substationsSet).build(); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNode2Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkEquipmentMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, expectedPayload); @@ -804,7 +826,7 @@ void testNetworkModificationEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); Pair> modificationBody = Pair.of(bodyJson, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNodeUuid, NETWORK_UUID))); @@ -824,7 +846,7 @@ void testNetworkModificationEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -874,7 +896,7 @@ void testCreateGenerator() throws Exception { .content(bodyJsonCreate).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -886,7 +908,7 @@ void testCreateGenerator() throws Exception { .content(bodyJsonCreate).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -950,7 +972,7 @@ void testCreateShuntsCompensator() throws Exception { .content(createShuntCompensatorAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1014,7 +1036,7 @@ void testCreateLine() throws Exception { .content(createLineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1026,7 +1048,7 @@ void testCreateLine() throws Exception { .content(createLineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); modificationBody = Pair.of(createLineAttributes, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNode2Uuid, NETWORK_UUID))); @@ -1097,7 +1119,7 @@ void testCreateTwoWindingsTransformer() throws Exception { .content(createTwoWindingsTransformerAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1109,7 +1131,7 @@ void testCreateTwoWindingsTransformer() throws Exception { .content(createTwoWindingsTransformerAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1219,7 +1241,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate1).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1234,7 +1256,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate2).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(stubPostId, modificationBodyJson); @@ -1248,7 +1270,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate3).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1263,7 +1285,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate4).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(stubPostId, modificationBodyJson); @@ -1277,7 +1299,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate5).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1292,7 +1314,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate6).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(stubPostId, modificationBodyJson); @@ -1306,7 +1328,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate7).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1321,7 +1343,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate8).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); wireMockStubs.verifyNetworkModificationPost(stubPostId, modificationBodyJson); @@ -1333,7 +1355,7 @@ void testUpdateLines() throws Exception { .content(bodyJsonCreate9).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1372,7 +1394,7 @@ void testCreateLoad() throws Exception { .content(createLoadAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1384,7 +1406,7 @@ void testCreateLoad() throws Exception { .content(createLoadAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1445,7 +1467,7 @@ void testModifyLoad() throws Exception { .content(loadModificationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1457,7 +1479,7 @@ void testModifyLoad() throws Exception { .content(loadModificationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1503,7 +1525,7 @@ void testModifyEquipment() throws Exception { .content(equipmentModificationAttribute).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1515,7 +1537,7 @@ void testModifyEquipment() throws Exception { .content(equipmentModificationAttribute).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid2); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1564,7 +1586,7 @@ void testCreateSubstation() throws Exception { .content(createSubstationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1576,7 +1598,7 @@ void testCreateSubstation() throws Exception { .content(createSubstationAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1636,7 +1658,7 @@ void testCreateVoltageLevel() throws Exception { .content(createVoltageLevelAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1648,7 +1670,7 @@ void testCreateVoltageLevel() throws Exception { .content(createVoltageLevelAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1710,7 +1732,7 @@ void testLineSplitWithVoltageLevel() throws Exception { .content(lineSplitWoVLasJSON).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1736,7 +1758,7 @@ void testLineSplitWithVoltageLevel() throws Exception { .content(badBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); mockMvc.perform(put(URI_NETWORK_MODIF_WITH_ID, studyNameUserIdUuid, modificationNodeUuid, MODIFICATION_UUID) @@ -1770,7 +1792,7 @@ void testLineAttachToVoltageLevel() throws Exception { .content(createLineAttachToVoltageLevelAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1805,7 +1827,7 @@ void testLinesAttachToSplitLines() throws Exception { .content(createLinesAttachToSplitLinesAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1831,7 +1853,7 @@ void testLinesAttachToSplitLines() throws Exception { .content(badBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); mockMvc.perform(put(URI_NETWORK_MODIF_WITH_ID, studyNameUserIdUuid, modificationNodeUuid, MODIFICATION_UUID) @@ -1863,7 +1885,7 @@ void testScaling(ModificationType scalingType) throws Exception { .content(requestBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -1888,7 +1910,7 @@ void testScaling(ModificationType scalingType) throws Exception { .content(requestBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().is4xxClientError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(stubPostId, modificationBodyJson); @@ -1919,7 +1941,7 @@ void testDeleteVoltageLevelOnline() throws Exception { .content(createDeleteVoltageLevelOnlineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); Pair> modificationBody = Pair.of(createDeleteVoltageLevelOnlineAttributes, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNodeUuid, NETWORK_UUID))); @@ -1942,7 +1964,7 @@ void testDeleteVoltageLevelOnline() throws Exception { mockMvc.perform(post(URI_NETWORK_MODIF, studyNameUserIdUuid, modificationNodeUuid).header(USER_ID_HEADER, userId) .content(badBody).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(stubIdPostErr, modificationBodyJson); @@ -1972,7 +1994,7 @@ void testDeleteAttachingline() throws Exception { .content(createDeleteAttachingLineAttributes).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); Pair> modificationBody = Pair.of(createDeleteAttachingLineAttributes, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNodeUuid, NETWORK_UUID))); @@ -1996,7 +2018,7 @@ void testDeleteAttachingline() throws Exception { .content(badBody).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isBadRequest()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(stubIdPostErr, modificationBodyJson); @@ -2034,7 +2056,7 @@ void testReorderModification() throws Exception { mockMvc.perform(put("/v1/studies/{studyUuid}/nodes/{nodeUuid}/network-modification/{modificationID}", studyNameUserIdUuid, modificationNodeUuid, modification1).header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentUpdatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2052,7 +2074,7 @@ void testReorderModification() throws Exception { mockMvc.perform(put("/v1/studies/{studyUuid}/nodes/{nodeUuid}/network-modification/{modificationID}?beforeUuid={modificationID2}", studyNameUserIdUuid, modificationNodeUuid, modification1, modification2).header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentUpdatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2116,7 +2138,7 @@ void testDuplicateModification() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkEquipmentUpdatingFinishedMessagesReceived(studyUuid, nodeUuid1); checkElementUpdatedMessageSent(studyUuid, userId); @@ -2149,7 +2171,7 @@ void testDuplicateModification() throws Exception { .andExpect(status().isOk()); NetworkImpactsInfos expectedPayload = NetworkImpactsInfos.builder().build(); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkElementUpdatedMessageSent(studyUuid, userId); checkEquipmentMessagesReceived(studyUuid, List.of(nodeUuid1), expectedPayload); @@ -2188,7 +2210,7 @@ void testDuplicateModificationBetweenStudies() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyEntity1.getId(), node1.getId()); + checkUpdateStatusMessagesReceived(studyEntity1.getId(), node1.getId(), output); checkEquipmentUpdatingMessagesReceived(studyEntity1.getId(), node1.getId()); checkEquipmentUpdatingFinishedMessagesReceived(studyEntity1.getId(), node1.getId()); checkElementUpdatedMessageSent(studyEntity1.getId(), userId); @@ -2269,7 +2291,7 @@ void testCutAndPasteModification() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkEquipmentUpdatingFinishedMessagesReceived(studyUuid, nodeUuid1); @@ -2289,8 +2311,8 @@ void testCutAndPasteModification() throws Exception { .content(modificationUuidListBody) .header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid1); - checkUpdateModelsStatusMessagesReceived(studyUuid, nodeUuid2); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid2, output); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid2); checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); checkEquipmentUpdatingFinishedMessagesReceived(studyUuid, nodeUuid2); @@ -2378,7 +2400,7 @@ void testDeleteEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2390,7 +2412,7 @@ void testDeleteEquipment() throws Exception { .content(bodyJson).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2452,7 +2474,7 @@ void testNodesInvalidation(final MockWebServer server) throws Exception { wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); checkEquipmentUpdatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkNodesInvalidationMessagesReceived(studyNameUserIdUuid, List.of(modificationNode1Uuid, modificationNode2Uuid, modificationNode3Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2486,7 +2508,7 @@ void testNodesInvalidation(final MockWebServer server) throws Exception { .andExpect(status().isOk()); wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); checkNodesInvalidationMessagesReceived(studyNameUserIdUuid, List.of(modificationNode2Uuid, modificationNode3Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode2Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2506,28 +2528,22 @@ void testRemoveLoadFlowComputationReport(final MockWebServer server) throws Exce UUID rootNodeUuid = getRootNode(studyNameUserIdUuid).getId(); NetworkModificationNode modificationNode1 = createNetworkModificationNode(studyNameUserIdUuid, rootNodeUuid, UUID.randomUUID(), VARIANT_ID, "node 1", NetworkModificationNodeType.SECURITY, BuildStatus.BUILT, userId); UUID modificationNode1Uuid = modificationNode1.getId(); - // In this node, let's say we have all computations results + // In this node, let's say we have all computation results RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity = rootNetworkNodeInfoRepository.findByNodeInfoIdAndRootNetworkId(modificationNode1Uuid, studyTestUtils.getOneRootNetworkUuid(studyNameUserIdUuid)).orElseThrow(() -> new StudyException(NOT_FOUND, "Root network not found")); rootNetworkNodeInfoEntity.setLoadFlowResultUuid(LOADFLOW_RESULT_UUID); rootNetworkNodeInfoEntity.setSecurityAnalysisResultUuid(UUID.fromString(SECURITY_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setDynamicSimulationResultUuid(DYNAMIC_SIMULATION_RESULT_UUID); rootNetworkNodeInfoEntity.setDynamicSecurityAnalysisResultUuid(DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID); + rootNetworkNodeInfoEntity.setDynamicMarginCalculationResultUuid(DYNAMIC_MARGIN_CALCULATION_RESULT_UUID); rootNetworkNodeInfoEntity.setSensitivityAnalysisResultUuid(UUID.fromString(SENSITIVITY_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setShortCircuitAnalysisResultUuid(UUID.fromString(SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setOneBusShortCircuitAnalysisResultUuid(UUID.fromString(ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID)); rootNetworkNodeInfoEntity.setVoltageInitResultUuid(UUID.fromString(VOLTAGE_INIT_RESULT_UUID)); rootNetworkNodeInfoEntity.setStateEstimationResultUuid(UUID.fromString(STATE_ESTIMATION_RESULT_UUID)); - rootNetworkNodeInfoEntity.setComputationReports(Map.of( - ComputationType.LOAD_FLOW.name(), UUID.randomUUID(), - ComputationType.SECURITY_ANALYSIS.name(), UUID.randomUUID(), - ComputationType.DYNAMIC_SIMULATION.name(), UUID.randomUUID(), - ComputationType.DYNAMIC_SECURITY_ANALYSIS.name(), UUID.randomUUID(), - ComputationType.SENSITIVITY_ANALYSIS.name(), UUID.randomUUID(), - ComputationType.SHORT_CIRCUIT.name(), UUID.randomUUID(), - ComputationType.SHORT_CIRCUIT_ONE_BUS.name(), UUID.randomUUID(), - ComputationType.VOLTAGE_INITIALIZATION.name(), UUID.randomUUID(), - ComputationType.STATE_ESTIMATION.name(), UUID.randomUUID() - )); + rootNetworkNodeInfoEntity.setPccMinResultUuid(UUID.fromString(PCC_MIN_RESULT_UUID)); + Map computationReportsMap = Arrays.stream(ComputationType.values()) + .collect(Collectors.toMap(ComputationType::name, computationType -> UUID.randomUUID())); + rootNetworkNodeInfoEntity.setComputationReports(computationReportsMap); rootNetworkNodeInfoRepository.save(rootNetworkNodeInfoEntity); // A modification body @@ -2548,7 +2564,7 @@ void testRemoveLoadFlowComputationReport(final MockWebServer server) throws Exce .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNode1Uuid)); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNode1Uuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2556,17 +2572,19 @@ void testRemoveLoadFlowComputationReport(final MockWebServer server) throws Exce wireMockStubs.verifyNetworkModificationPostWithVariant(stubPostId, getModificationContextJsonString(mapper, modificationBody)); wireMockStubs.verifyNetworkModificationDeleteIndex(deleteModificationIndexStub); - var requests = TestUtils.getRequestsDone(20, server); // 1 status LF + 2 x 9 computations + 1 report + var requests = TestUtils.getRequestsDone(24, server); // 1 status LF + 2 x 11 computations + 1 report List.of( LOADFLOW_RESULT_UUID, SECURITY_ANALYSIS_RESULT_UUID, DYNAMIC_SIMULATION_RESULT_UUID, DYNAMIC_SECURITY_ANALYSIS_RESULT_UUID, + DYNAMIC_MARGIN_CALCULATION_RESULT_UUID, SENSITIVITY_ANALYSIS_RESULT_UUID, SHORTCIRCUIT_ANALYSIS_RESULT_UUID, ONE_BUS_SHORTCIRCUIT_ANALYSIS_RESULT_UUID, VOLTAGE_INIT_RESULT_UUID, - STATE_ESTIMATION_RESULT_UUID + STATE_ESTIMATION_RESULT_UUID, + PCC_MIN_RESULT_UUID ).forEach(uuid -> { assertTrue(requests.stream().anyMatch(r -> r.equals("/v1/results?resultsUuids=" + uuid))); assertTrue(requests.stream().anyMatch(r -> r.equals("/v1/results/" + uuid + "/status"))); @@ -2595,7 +2613,7 @@ void testUpdateOfBuildStatus() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -2617,7 +2635,7 @@ void testUpdateOfBuildStatus() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); NetworkImpactsInfos expectedPayload = NetworkImpactsInfos.builder().impactedSubstationsIds(ImmutableSet.of("s1")).deletedEquipments(ImmutableSet.of()).build(); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkEquipmentMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, expectedPayload); @@ -2633,7 +2651,7 @@ void testUpdateOfBuildStatus() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNodeUuid)); @@ -2650,7 +2668,7 @@ void testUpdateOfBuildStatus() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(modificationNodeUuid)); @@ -2798,31 +2816,6 @@ private void checkEquipmentCreatingMessagesReceived(UUID studyNameUserIdUuid, UU assertEquals(NotificationService.MODIFICATIONS_CREATING_IN_PROGRESS, headersStudyUpdate.get(NotificationService.HEADER_UPDATE_TYPE)); } - private void checkUpdateModelStatusMessagesReceived(UUID studyUuid, UUID nodeUuid, String updateType) { - // assert that the broker message has been sent for updating model status - Message messageStatus = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); - assertEquals("", new String(messageStatus.getPayload())); - MessageHeaders headersStatus = messageStatus.getHeaders(); - assertEquals(studyUuid, headersStatus.get(NotificationService.HEADER_STUDY_UUID)); - if (nodeUuid != null) { - assertEquals(nodeUuid, headersStatus.get(NotificationService.HEADER_NODE)); - } - assertEquals(updateType, headersStatus.get(NotificationService.HEADER_UPDATE_TYPE)); - } - - private void checkUpdateModelsStatusMessagesReceived(UUID studyUuid, UUID nodeUuid) { - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_LOADFLOW_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SENSITIVITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_SHORT_CIRCUIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_ONE_BUS_SHORT_CIRCUIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_VOLTAGE_INIT_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SIMULATION_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_DYNAMIC_SECURITY_ANALYSIS_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_STATE_ESTIMATION_STATUS); - checkUpdateModelStatusMessagesReceived(studyUuid, nodeUuid, NotificationService.UPDATE_TYPE_PCC_MIN_STATUS); - } - private void checkNodesBuildStatusUpdatedMessageReceived(UUID studyUuid, List nodesUuids) { Message messageStatus = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); assertEquals("", new String(messageStatus.getPayload())); @@ -2833,7 +2826,7 @@ private void checkNodesBuildStatusUpdatedMessageReceived(UUID studyUuid, List messageStudyUpdate = output.receive(TIMEOUT, STUDY_UPDATE_DESTINATION); - NetworkImpactsInfos actualPayload = mapper.readValue(new String(messageStudyUpdate.getPayload()), new TypeReference() { }); - assertThat(expectedPayload, new MatcherJson<>(mapper, actualPayload)); - MessageHeaders headersStudyUpdate = messageStudyUpdate.getHeaders(); - assertEquals(studyNameUserIdUuid, headersStudyUpdate.get(NotificationService.HEADER_STUDY_UUID)); - assertEquals(nodeUuid, headersStudyUpdate.get(NotificationService.HEADER_NODE)); - assertEquals(NotificationService.UPDATE_TYPE_STUDY, headersStudyUpdate.get(NotificationService.HEADER_UPDATE_TYPE)); - - checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, List.of(nodeUuid)); - - // assert that the broker message has been sent for updating load flow status - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, nodeUuid); - } - private void checkNodesInvalidationMessagesReceived(UUID studyNameUserIdUuid, List invalidatedNodes) { checkNodesBuildStatusUpdatedMessageReceived(studyNameUserIdUuid, invalidatedNodes); } @@ -2995,7 +2972,7 @@ void testCreateModificationWithErrors() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isOk()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkElementUpdatedMessageSent(studyNameUserIdUuid, userId); @@ -3010,7 +2987,7 @@ void testCreateModificationWithErrors() throws Exception { .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()) .andReturn(); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(stubId, modificationBodyJson); @@ -3021,7 +2998,7 @@ void testCreateModificationWithErrors() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(stubId, modificationBodyJson); @@ -3033,7 +3010,7 @@ void testCreateModificationWithErrors() throws Exception { .content(jsonCreateLoadInfos).contentType(MediaType.APPLICATION_JSON) .header(USER_ID_HEADER, userId)) .andExpect(status().isInternalServerError()); - checkUpdateModelsStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); + checkUpdateStatusMessagesReceived(studyNameUserIdUuid, modificationNodeUuid, output); checkEquipmentCreatingMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); checkEquipmentUpdatingFinishedMessagesReceived(studyNameUserIdUuid, modificationNodeUuid); wireMockStubs.verifyNetworkModificationPost(stubId, modificationBodyJson); diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java index 1b1a57f7cb..c8ec708e92 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java @@ -28,6 +28,7 @@ import mockwebserver3.junit5.internal.MockWebServerExtension; import okhttp3.Headers; import okhttp3.HttpUrl; +import org.gridsuite.study.server.dto.ComputationType; import org.gridsuite.study.server.dto.RootNetworkNodeInfo; import org.gridsuite.study.server.dto.modification.NetworkModificationResult; import org.gridsuite.study.server.error.StudyException; @@ -43,9 +44,9 @@ import org.gridsuite.study.server.repository.rootnetwork.RootNetworkNodeInfoRepository; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkRepository; import org.gridsuite.study.server.service.*; +import org.gridsuite.study.server.service.client.dynamicmargincalculation.DynamicMarginCalculationClient; import org.gridsuite.study.server.service.client.dynamicsecurityanalysis.DynamicSecurityAnalysisClient; import org.gridsuite.study.server.service.client.dynamicsimulation.DynamicSimulationClient; -import org.gridsuite.study.server.service.LoadFlowService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; import org.gridsuite.study.server.utils.TestUtils; import org.gridsuite.study.server.utils.elasticsearch.DisableElasticsearch; @@ -75,12 +76,16 @@ import java.util.*; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NOT_FOUND; import static org.gridsuite.study.server.notification.NotificationService.*; import static org.gridsuite.study.server.service.NetworkModificationTreeService.ROOT_NODE_NAME; +import static org.gridsuite.study.server.utils.TestUtils.checkUpdateStatusMessagesReceived; +import static org.gridsuite.study.server.utils.TestUtils.checkUpdateTypeMessageReceived; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.BDDMockito.given; @@ -175,6 +180,9 @@ class NetworkModificationTreeTest { @MockitoSpyBean DynamicSecurityAnalysisClient dynamicSecurityAnalysisClient; + @MockitoSpyBean + DynamicMarginCalculationClient dynamicMarginCalculationClient; + @MockitoBean private NetworkStoreService networkStoreService; @@ -266,6 +274,7 @@ public Set