diff --git a/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java b/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java index 5cd769067..d5bc286b0 100644 --- a/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java +++ b/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.commons.lang3.tuple.Pair; import org.gridsuite.modification.NetworkModificationException; import org.gridsuite.modification.dto.ModificationInfos; import org.gridsuite.modification.server.dto.*; @@ -71,12 +72,41 @@ public ResponseEntity getNetworkModificationsCount(@Parameter(descripti @PostMapping(value = "/groups") @Operation(summary = "Create a modification group based on another group") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The group and its modifications have been duplicated")}) - public ResponseEntity createModificationGroup(@RequestParam("groupUuid") UUID groupUuid, - @RequestParam("duplicateFrom") UUID sourceGroupUuid) { - networkModificationService.createModificationGroup(sourceGroupUuid, groupUuid); + public ResponseEntity duplicateGroup(@RequestParam("groupUuid") UUID groupUuid, + @RequestParam("duplicateFrom") UUID sourceGroupUuid) { + networkModificationService.duplicateGroup(sourceGroupUuid, groupUuid); return ResponseEntity.ok().build(); } + @PutMapping(value = "/groups/{groupUuid}", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "For a list of network modifications passed in body, Move them before another one or at the end of the list, or Duplicate them at the end of the list") + @ApiResponse(responseCode = "200", description = "The modification list of the group has been updated.") + public ResponseEntity>> handleNetworkModifications(@Parameter(description = "updated group UUID, where modifications are pasted") @PathVariable("groupUuid") UUID targetGroupUuid, + @Parameter(description = "kind of modification", required = true) @RequestParam(value = "action") GroupModificationAction action, + @Parameter(description = "the modification Uuid to move before (MOVE option, empty means moving at the end)") @RequestParam(value = "before", required = false) UUID beforeModificationUuid, + @Parameter(description = "origin group UUID, where modifications are copied or cut") @RequestParam(value = "originGroupUuid", required = false) UUID originGroupUuid, + @Parameter(description = "destination node can be built (default is true)") @RequestParam(value = "build", required = false, defaultValue = "true") Boolean build, + @RequestBody Pair, List> modificationContextInfos) { + return switch (action) { + case COPY -> + ResponseEntity.ok().body(networkModificationService.duplicateModifications(targetGroupUuid, modificationContextInfos.getLeft(), modificationContextInfos.getRight())); + case INSERT -> + ResponseEntity.ok().body(networkModificationService.insertCompositeModifications(targetGroupUuid, modificationContextInfos.getLeft(), modificationContextInfos.getRight())); + case MOVE -> { + UUID sourceGroupUuid = originGroupUuid == null ? targetGroupUuid : originGroupUuid; + boolean canBuildNode = build; + if (sourceGroupUuid.equals(targetGroupUuid)) { + canBuildNode = false; + } + yield ResponseEntity.ok().body(networkModificationService.moveModifications(targetGroupUuid, sourceGroupUuid, beforeModificationUuid, modificationContextInfos.getLeft(), modificationContextInfos.getRight(), canBuildNode)); + } + }; + } + + /** + * TODO : Remove this endpoint after the final integration of root networks (used only for move and tests) + * Need to use the new endpoint with modificationContextInfos DTO (see above) + */ @PutMapping(value = "/groups/{groupUuid}", params = {"networkUuid", "reportUuid", "reporterId"}, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "For a list of network modifications passed in body, Move them before another one or at the end of the list, or Duplicate them at the end of the list") @ApiResponse(responseCode = "200", description = "The modification list of the group has been updated.") @@ -123,72 +153,36 @@ public ResponseEntity> getModificationGroups() { return ResponseEntity.ok().body(networkModificationService.getModificationGroups()); } - @PostMapping(value = "/network-modifications", params = {"networkUuid", "reportUuid", "reporterId"}, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/network-modifications", params = "groupUuid", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Create a network modification") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "The network modification was created"), @ApiResponse(responseCode = "404", description = "The network or equipment was not found")}) - public ResponseEntity> createNetworkModification( - @Parameter(description = "Network UUID") @RequestParam("networkUuid") UUID networkUuid, - @Parameter(description = "Variant ID") @RequestParam(name = "variantId", required = false) String variantId, - @Parameter(description = "Group UUID") @RequestParam(name = "groupUuid", required = false) UUID groupUuid, - @Parameter(description = "Report UUID") @RequestParam("reportUuid") UUID reportUuid, - @Parameter(description = "Reporter ID") @RequestParam("reporterId") String reporterId, - @RequestBody ModificationInfos modificationInfos) { - modificationInfos.check(); - return ResponseEntity.ok().body(networkModificationService.createNetworkModification(networkUuid, variantId, groupUuid, new ReportInfos(reportUuid, UUID.fromString(reporterId)), modificationInfos)); + public ResponseEntity>> createNetworkModification( + @Parameter(description = "Group UUID") @RequestParam(name = "groupUuid") UUID groupUuid, + @RequestBody Pair> modificationContextInfos) { + modificationContextInfos.getLeft().check(); + return ResponseEntity.ok().body(networkModificationService.createNetworkModification(groupUuid, modificationContextInfos.getLeft(), modificationContextInfos.getRight())); } /** - * Temporary endpoint linked to root network implementation - * This endpoint creates a modification without applying it, and returning its UUID in order to apply it later + * TODO : Remove this endpoint after the final integration of root networks (all tests need to migrate before) + * Need to use tne new endpoint with modificationContextInfos DTO (see above) */ - @PostMapping(value = "/network-modifications", params = "groupUuid", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/network-modifications", params = {"networkUuid", "reportUuid", "reporterId"}, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Create a network modification") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "The network modification was created"), @ApiResponse(responseCode = "404", description = "The network or equipment was not found")}) - public ResponseEntity> createNetworkModificationWithoutApplying( - @Parameter(description = "Group UUID") @RequestParam(name = "groupUuid") UUID groupUuid, + public ResponseEntity> createNetworkModification( + @Parameter(description = "Network UUID") @RequestParam("networkUuid") UUID networkUuid, + @Parameter(description = "Variant ID") @RequestParam(name = "variantId", required = false) String variantId, + @Parameter(description = "Group UUID") @RequestParam(name = "groupUuid", required = false) UUID groupUuid, + @Parameter(description = "Report UUID") @RequestParam("reportUuid") UUID reportUuid, + @Parameter(description = "Reporter ID") @RequestParam("reporterId") String reporterId, @RequestBody ModificationInfos modificationInfos) { modificationInfos.check(); - return ResponseEntity.ok().body(networkModificationService.createNetworkModification(groupUuid, modificationInfos)); - } - - /** - * Temporary endpoint linked to root network implementation - * This endpoint creates a modification without applying it, and returning its UUID in order to apply it later - */ - @PutMapping(value = "/groups/{groupUuid}", produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "For a list of network modifications passed in body, Move them before another one or at the end of the list, or Duplicate them at the end of the list") - @ApiResponse(responseCode = "200", description = "The modification list of the group has been updated.") - public ResponseEntity> handleNetworkModificationsWithoutApplying(@Parameter(description = "updated group UUID, where modifications are pasted") @PathVariable("groupUuid") UUID targetGroupUuid, - @Parameter(description = "kind of modification", required = true) @RequestParam(value = "action") GroupModificationAction action, - @Parameter(description = "the modification Uuid to move before (MOVE option, empty means moving at the end)") @RequestParam(value = "before", required = false) UUID beforeModificationUuid, - @Parameter(description = "origin group UUID, where modifications are copied or cut") @RequestParam(value = "originGroupUuid", required = false) UUID originGroupUuid, - @RequestBody List modificationsUuidList) { - return switch (action) { - case COPY -> - ResponseEntity.ok().body(networkModificationService.duplicateModifications(targetGroupUuid, modificationsUuidList)); - case INSERT -> - ResponseEntity.ok().body(networkModificationService.insertCompositeModifications(targetGroupUuid, modificationsUuidList)); - case MOVE -> { - UUID sourceGroupUuid = originGroupUuid == null ? targetGroupUuid : originGroupUuid; - yield ResponseEntity.ok().body(networkModificationService.moveModifications(targetGroupUuid, sourceGroupUuid, beforeModificationUuid, modificationsUuidList)); - } - }; - } - - /** - * Temporary endpoint linked to root network implementation - * This endpoint applied a list of modifications to multiple network variants, then return ordered impacts on those networks variants - */ - @PostMapping(value = "/network-modifications/apply", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Apply a list of modifications to a list of network contexts") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The network modification was updated")}) - public ResponseEntity>> applyNetworkModification( - @RequestBody MultipleNetworkModificationsInfos multipleNetworkModificationsInfos) { - return ResponseEntity.ok().body(networkModificationService.applyNetworkModifications(multipleNetworkModificationsInfos)); + return ResponseEntity.ok().body(networkModificationService.createNetworkModification(networkUuid, variantId, groupUuid, new ReportInfos(reportUuid, UUID.fromString(reporterId)), modificationInfos)); } @PutMapping(value = "/network-modifications/{uuid}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) diff --git a/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationContextInfos.java b/src/main/java/org/gridsuite/modification/server/dto/ModificationApplicationContext.java similarity index 74% rename from src/main/java/org/gridsuite/modification/server/dto/NetworkModificationContextInfos.java rename to src/main/java/org/gridsuite/modification/server/dto/ModificationApplicationContext.java index cb0c7d760..52addfe2c 100644 --- a/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationContextInfos.java +++ b/src/main/java/org/gridsuite/modification/server/dto/ModificationApplicationContext.java @@ -8,4 +8,4 @@ import java.util.UUID; -public record NetworkModificationContextInfos(UUID networkUuid, String variantId, UUID reportUuid, UUID nodeUuid) { } +public record ModificationApplicationContext(UUID networkUuid, String variantId, UUID reportUuid, UUID nodeUuid) { } diff --git a/src/main/java/org/gridsuite/modification/server/dto/MultipleNetworkModificationsInfos.java b/src/main/java/org/gridsuite/modification/server/dto/MultipleNetworkModificationsInfos.java deleted file mode 100644 index 17e6aeb5a..000000000 --- a/src/main/java/org/gridsuite/modification/server/dto/MultipleNetworkModificationsInfos.java +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) 2024, 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.modification.server.dto; - -import java.util.List; -import java.util.UUID; - -public record MultipleNetworkModificationsInfos(List modificationsUuid, List networkModificationContextInfos) { } diff --git a/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java index 49e1e6aac..6d6e4b4b1 100644 --- a/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java @@ -146,6 +146,16 @@ public void restoreNetworkModifications(UUID groupUuid, @NonNull List modi // No transactional because we need to save modification in DB also in case of error // Transaction made in 'saveModifications' method // TODO Add transaction when errors will no longer be sent to the front + public List> createNetworkModification(@NonNull UUID groupUuid, @NonNull ModificationInfos modificationInfo, @NonNull List applicationContexts) { + networkModificationRepository.saveModificationInfos(groupUuid, List.of(modificationInfo)).stream().map(ModificationEntity::getId).findFirst(); + + return applyModifications(List.of(modificationInfo), applicationContexts); + } + + /** + * TODO : Remove this endpoint after the final integration of root networks + * Need to use tne new endpoint with ModificationApplicationContext DTO (see above) + */ public Optional createNetworkModification(@NonNull UUID networkUuid, String variantId, @NonNull UUID groupUuid, @NonNull ReportInfos reportInfos, @NonNull ModificationInfos modificationInfos) { @@ -159,53 +169,14 @@ public Optional createNetworkModification(@NonNull UU } /** - * Temporary method linked to root network implementation - */ - public Optional createNetworkModification(@NonNull UUID groupUuid, @NonNull ModificationInfos modificationInfos) { - return networkModificationRepository.saveModificationInfos(groupUuid, List.of(modificationInfos)).stream().map(ModificationEntity::getId).findFirst(); - } - - /** - * Temporary method linked to root network implementation - */ - @Transactional - public List duplicateModifications(UUID targetGroupUuid, - List modificationsUuids) { - List modificationInfos = networkModificationRepository.getModificationsInfos(modificationsUuids); - return networkModificationRepository.saveModificationInfos(targetGroupUuid, modificationInfos).stream().map(ModificationEntity::getId).toList(); - } - - /** - * Temporary method linked to root network implementation - */ - @Transactional - public List insertCompositeModifications(UUID targetGroupUuid, - List modificationsUuids) { - List modificationInfos = networkModificationRepository.getCompositeModificationsInfos(modificationsUuids); - return networkModificationRepository.saveModificationInfos(targetGroupUuid, modificationInfos).stream().map(ModificationEntity::getId).toList(); - } - - /** - * Temporary method linked to root network implementation - */ - @Transactional - public List moveModifications(UUID destinationGroupUuid, UUID originGroupUuid, - UUID beforeModificationUuid, List modificationsToMove) { - // update origin/destinations groups to cut and paste all modificationsToMove - return networkModificationRepository.moveModifications(destinationGroupUuid, originGroupUuid, modificationsToMove, beforeModificationUuid).stream().map(ModificationEntity::getId).toList(); - } - - /** - * Temporary method linked to root network implementation + * Apply modifications on several networks */ - public List> applyNetworkModifications(MultipleNetworkModificationsInfos multipleNetworkModificationsInfos) { - List modificationsToApply = networkModificationRepository.getModificationsInfos(multipleNetworkModificationsInfos.modificationsUuid()); - return multipleNetworkModificationsInfos.networkModificationContextInfos().stream().map(networkModificationContextInfos -> - applyModifications(networkModificationContextInfos.networkUuid(), - networkModificationContextInfos.variantId(), - new ReportInfos(networkModificationContextInfos.reportUuid(), - networkModificationContextInfos.nodeUuid()), - modificationsToApply) + private List> applyModifications(List modifications, List applicationContexts) { + return applicationContexts.stream().map(modificationApplicationContext -> + applyModifications(modificationApplicationContext.networkUuid(), + modificationApplicationContext.variantId(), + new ReportInfos(modificationApplicationContext.reportUuid(), modificationApplicationContext.nodeUuid()), + modifications) ).toList(); } @@ -281,6 +252,22 @@ public void deleteNetworkModifications(UUID groupUuid, List modificationsU } } + @Transactional + public List> moveModifications(@NonNull UUID destinationGroupUuid, @NonNull UUID originGroupUuid, @NonNull UUID beforeModificationUuid, + @NonNull List modificationsToMoveUuids, @NonNull List applicationContexts, + boolean canBuildNode) { + // update origin/destinations groups to cut and paste all modificationsToMove + List modificationInfos = networkModificationRepository.moveModifications(destinationGroupUuid, originGroupUuid, modificationsToMoveUuids, beforeModificationUuid).stream() + .map(networkModificationRepository::getModificationInfos) + .toList(); + + return canBuildNode && !modificationInfos.isEmpty() ? applyModifications(modificationInfos, applicationContexts) : List.of(); + } + + /** + * TODO : Remove this endpoint after the final integration of root networks + * Need to use the new endpoint with ModificationApplicationContext DTO (see above) + */ @Transactional public Optional moveModifications(UUID destinationGroupUuid, UUID originGroupUuid, UUID beforeModificationUuid, UUID networkUuid, String variantId, @@ -291,22 +278,22 @@ public Optional moveModifications(UUID destinationGro if (canBuildNode && !movedEntities.isEmpty()) { // TODO remove canBuildNode ? // try to apply the moved modifications only (incremental mode) PreloadingStrategy preloadingStrategy = movedEntities.stream() - .map(e -> ModificationType.valueOf(e.getType())) - .reduce(ModificationType::maxStrategy).map(ModificationType::getStrategy).orElse(PreloadingStrategy.NONE); + .map(e -> ModificationType.valueOf(e.getType())) + .reduce(ModificationType::maxStrategy).map(ModificationType::getStrategy).orElse(PreloadingStrategy.NONE); NetworkInfos networkInfos = getNetworkInfos(networkUuid, variantId, preloadingStrategy); if (networkInfos.isVariantPresent()) { List movedModifications = movedEntities.stream() - .map(networkModificationRepository::getModificationInfos).toList(); + .map(networkModificationRepository::getModificationInfos).toList(); return Optional.of(modificationApplicator.applyModifications( - movedModifications, - networkInfos, - reportInfos)); + movedModifications, + networkInfos, + reportInfos)); } } return Optional.empty(); } - public void createModificationGroup(UUID sourceGroupUuid, UUID groupUuid) { + public void duplicateGroup(UUID sourceGroupUuid, UUID groupUuid) { try { networkModificationRepository.saveModificationInfos(groupUuid, networkModificationRepository.getActiveModificationsInfos(sourceGroupUuid)); } catch (NetworkModificationException e) { @@ -337,6 +324,17 @@ private Optional applyModifications(UUID networkUuid, return Optional.empty(); } + @Transactional + public List> duplicateModifications(@NonNull UUID targetGroupUuid, @NonNull List modificationsUuids, @NonNull List applicationContexts) { + List modificationInfos = networkModificationRepository.getModificationsInfos(modificationsUuids); + networkModificationRepository.saveModificationInfos(targetGroupUuid, modificationInfos); + return applyModifications(modificationInfos, applicationContexts); + } + + /** + * TODO : Remove this endpoint after the final integration of root networks + * Need to use the new endpoint with ModificationApplicationContext DTO (see above) + */ @Transactional public Optional duplicateModifications(UUID targetGroupUuid, UUID networkUuid, String variantId, @@ -346,6 +344,17 @@ public Optional duplicateModifications(UUID targetGro return applyModifications(networkUuid, variantId, reportInfos, modificationInfos); } + @Transactional + public List> insertCompositeModifications(@NonNull UUID targetGroupUuid, @NonNull List modificationsUuids, @NonNull List applicationContexts) { + List modificationInfos = networkModificationRepository.getCompositeModificationsInfos(modificationsUuids); + networkModificationRepository.saveModificationInfos(targetGroupUuid, modificationInfos); + return applyModifications(modificationInfos, applicationContexts); + } + + /** + * TODO : Remove this endpoint after the final integration of root networks (used only for move) + * Need to use the new endpoint with ModificationApplicationContext DTO (see above) + */ @Transactional public Optional insertCompositeModifications(UUID targetGroupUuid, UUID networkUuid, String variantId, diff --git a/src/test/java/org/gridsuite/modification/server/ModificationControllerUnitTest.java b/src/test/java/org/gridsuite/modification/server/ModificationControllerUnitTest.java deleted file mode 100644 index 7dbc64a15..000000000 --- a/src/test/java/org/gridsuite/modification/server/ModificationControllerUnitTest.java +++ /dev/null @@ -1,268 +0,0 @@ -package org.gridsuite.modification.server; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.powsybl.iidm.network.Country; -import com.powsybl.iidm.network.IdentifiableType; -import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.VariantManager; -import com.powsybl.network.store.client.NetworkStoreService; -import com.powsybl.network.store.client.PreloadingStrategy; -import org.gridsuite.modification.dto.*; -import org.gridsuite.modification.server.dto.*; -import org.gridsuite.modification.server.entities.ModificationEntity; -import org.gridsuite.modification.server.entities.equipment.modification.attribute.EquipmentAttributeModificationEntity; -import org.gridsuite.modification.server.modifications.NetworkModificationApplicator; -import org.gridsuite.modification.server.repositories.ModificationRepository; -import org.gridsuite.modification.server.repositories.NetworkModificationRepository; -import org.gridsuite.modification.server.utils.elasticsearch.DisableElasticsearch; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; - -import java.util.List; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@AutoConfigureMockMvc -@SpringBootTest -@DisableElasticsearch -class ModificationControllerUnitTest { - private static final String URI_NETWORK_MODIF_BASE = "/v1/network-modifications"; - private static final String URI_GROUP_MODIF_BASE = "/v1/groups"; - - @Autowired - MockMvc mockMvc; - - @Autowired - ObjectMapper objectMapper; - - @MockBean - NetworkStoreService networkStoreService; - - @Autowired - private ModificationRepository modificationRepository; - - @SpyBean - private NetworkModificationRepository networkModificationRepository; - - @Captor - ArgumentCaptor> modificationInfosCaptor; - - @Captor - ArgumentCaptor networkInfoCaptor; - - @Captor - ArgumentCaptor reportInfosCaptor; - - @SpyBean - private NetworkModificationApplicator networkModificationApplicator; - - @Mock - private Network network; - - @Mock - private VariantManager variantManager; - - @Test - void testCreateModificationWithoutApplying() throws Exception { - UUID groupUuid = UUID.randomUUID(); - EquipmentAttributeModificationInfos switchStatusModificationInfos = EquipmentAttributeModificationInfos.builder() - .equipmentType(IdentifiableType.SWITCH) - .equipmentAttributeName("open") - .equipmentId("v1b1") - .equipmentAttributeValue(true) - .build(); - - MvcResult mvcResult = mockMvc.perform(post(URI_NETWORK_MODIF_BASE) - .param("groupUuid", groupUuid.toString()) - .content(objectMapper.writeValueAsString(switchStatusModificationInfos)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andReturn(); - - UUID result = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), UUID.class); - - List modificationEntityList = modificationRepository.findAllByGroupId(groupUuid, false); - assertEquals(1, modificationEntityList.size()); - EquipmentAttributeModificationEntity modificationEntity = (EquipmentAttributeModificationEntity) modificationEntityList.get(0); - assertEquals("open", modificationEntity.getAttributeName()); - assertEquals("v1b1", modificationEntity.getEquipmentId()); - assertEquals(result, modificationEntity.getId()); - - // since we're not applying the modification, no network should have been loaded - Mockito.verify(networkStoreService, never()).getNetwork(any(), any()); - } - - @Test - void testApplyExistingModification() throws Exception { - // insert modifications in database - we assume they already exist for this test - UUID groupUuid = UUID.randomUUID(); - List modificationEntities = insertMultipleModifications(groupUuid); - - // define multiple network context - NetworkModificationContextInfos networkContext1 = new NetworkModificationContextInfos(UUID.randomUUID(), "variant1", UUID.randomUUID(), UUID.randomUUID()); - NetworkModificationContextInfos networkContext2 = new NetworkModificationContextInfos(UUID.randomUUID(), "variant2", UUID.randomUUID(), UUID.randomUUID()); - - // apply switchStatusModificationInfos and loadCreationInfos on those network contexts - MultipleNetworkModificationsInfos multipleNetworkModificationsInfos = new MultipleNetworkModificationsInfos( - List.of(modificationEntities.get(0).getId(), modificationEntities.get(2).getId()), - List.of(networkContext1, networkContext2) - ); - - Mockito.doReturn(NetworkModificationResult.builder().applicationStatus(NetworkModificationResult.ApplicationStatus.ALL_OK).build()) - .when(networkModificationApplicator).applyModifications(any(), any(), any()); - - when(networkStoreService.getNetwork(any(UUID.class), any(PreloadingStrategy.class))).thenReturn(network); - when(network.getVariantManager()).thenReturn(variantManager); - when(variantManager.getVariantIds()).thenReturn(List.of(networkContext1.variantId(), networkContext2.variantId())); - - mockMvc.perform(post(URI_NETWORK_MODIF_BASE + "/apply") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(multipleNetworkModificationsInfos))) - .andExpect(status().isOk()); - - // there should be as many "applyModifications" calls as the number of network contexts - Mockito.verify(networkModificationApplicator, times(multipleNetworkModificationsInfos.networkModificationContextInfos().size())) - .applyModifications(modificationInfosCaptor.capture(), networkInfoCaptor.capture(), reportInfosCaptor.capture()); - - // for each network context - multipleNetworkModificationsInfos.networkModificationContextInfos().forEach(networkContext -> { - // check "applyModifications" report infos match networkContext one - assertTrue(reportInfosCaptor.getAllValues().stream().anyMatch(reportInfos -> - reportInfos.getReportUuid().equals(networkContext.reportUuid()) && reportInfos.getNodeUuid().equals(networkContext.nodeUuid()) - )); - - // check "applyModifications" network infos match networkContext one - assertTrue(networkInfoCaptor.getAllValues().stream().anyMatch(networkInfo -> networkInfo.getNetworkUuuid().equals(networkContext.networkUuid()))); - }); - - // check "applyModifications" modification uuids match multipleNetworkModificationsInfos one - modificationInfosCaptor.getAllValues().forEach(modificationInfos -> - assertThat(multipleNetworkModificationsInfos.modificationsUuid()).usingRecursiveComparison().isEqualTo(List.of(modificationEntities.get(0).getId(), modificationEntities.get(2).getId())) - ); - } - - @Test - void testDuplicateModificationsWithoutApplying() throws Exception { - // prepare test - create modification in origin group - UUID originGroupUuid = UUID.randomUUID(); - List modificationEntities = insertMultipleModifications(originGroupUuid); - - // duplicate them into target group UUID - UUID targetGroupUuid = UUID.randomUUID(); - List modificationToDuplicateUuids = modificationEntities.stream().map(ModificationEntity::getId).toList(); - MvcResult mvcResult = mockMvc.perform(put(URI_GROUP_MODIF_BASE + "/{groupUuid}", targetGroupUuid.toString()) - .param("action", NetworkModificationController.GroupModificationAction.COPY.name()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(modificationToDuplicateUuids))) - .andExpect(status().isOk()) - .andReturn(); - - // check returned UUIDs matched what is stored in database - List result = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); - List expectedResult = modificationRepository.findAllByGroupId(targetGroupUuid, false).stream().map(ModificationEntity::getId).toList(); - assertThat(result).usingRecursiveComparison().isEqualTo(expectedResult); - assertEquals(3, expectedResult.size()); - - // check origin group modifications are still here - assertEquals(3, modificationRepository.findAllByGroupId(originGroupUuid, false).size()); - - // since we're not applying the modification, no network should have been loaded - Mockito.verify(networkStoreService, never()).getNetwork(any(), any()); - } - - @Test - void testMoveModificationsWithoutApplying() throws Exception { - // prepare test - create modification in origin group - UUID originGroupUuid = UUID.randomUUID(); - List modificationEntities = insertMultipleModifications(originGroupUuid); - - // move them into target group UUID - UUID targetGroupUuid = UUID.randomUUID(); - List modificationToDuplicateUuids = modificationEntities.stream().map(ModificationEntity::getId).toList(); - MvcResult mvcResult = mockMvc.perform(put(URI_GROUP_MODIF_BASE + "/{groupUuid}", targetGroupUuid.toString()) - .param("originGroupUuid", originGroupUuid.toString()) - .param("action", NetworkModificationController.GroupModificationAction.MOVE.name()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(modificationToDuplicateUuids))) - .andExpect(status().isOk()) - .andReturn(); - - // check returned UUIDs matched what is stored in database - List result = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); - List expectedResult = modificationRepository.findAllByGroupId(targetGroupUuid, false).stream().map(ModificationEntity::getId).toList(); - assertThat(result).usingRecursiveComparison().isEqualTo(expectedResult); - assertEquals(3, expectedResult.size()); - - // check origin group modifications are not here anymore - assertEquals(0, modificationRepository.findAllByGroupId(originGroupUuid, false).size()); - - // since we're not applying the modification, no network should have been loaded - Mockito.verify(networkStoreService, never()).getNetwork(any(), any()); - } - - @Test - void testInsertCompositeModificationsWithoutApplying() throws Exception { - // prepare test - create composite modification that will be used for mocking - UUID originGroupUuid = UUID.randomUUID(); - List modificationEntities = insertMultipleModifications(originGroupUuid); - - UUID compositeModificationUuid = UUID.randomUUID(); - Mockito.doReturn(List.of(CompositeModificationInfos.builder().modifications(modificationEntities.stream().map(ModificationEntity::toModificationInfos).toList()).build())) - .when(networkModificationRepository).getCompositeModificationsInfos(List.of(compositeModificationUuid)); - - // insert it into target group UUID - UUID targetGroupUuid = UUID.randomUUID(); - MvcResult mvcResult = mockMvc.perform(put(URI_GROUP_MODIF_BASE + "/{groupUuid}", targetGroupUuid.toString()) - .param("action", NetworkModificationController.GroupModificationAction.INSERT.name()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(List.of(compositeModificationUuid)))) - .andExpect(status().isOk()) - .andReturn(); - - // check returned UUID matched what is stored in database - List result = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); - List expectedResult = modificationRepository.findAllByGroupId(targetGroupUuid, false).stream().map(ModificationEntity::getId).toList(); - assertThat(result).usingRecursiveComparison().isEqualTo(expectedResult); - assertEquals(1, expectedResult.size()); - - // since we're not the modification, no network should have been loaded - Mockito.verify(networkStoreService, never()).getNetwork(any(), any()); - } - - private List insertMultipleModifications(UUID groupUuid) { - // insert modifications in database - we assume they already exist for this test - EquipmentAttributeModificationInfos switchStatusModificationInfos = EquipmentAttributeModificationInfos.builder() - .equipmentType(IdentifiableType.SWITCH) - .equipmentAttributeName("open") - .equipmentId("v1b1") - .equipmentAttributeValue(true) - .build(); - SubstationCreationInfos substationCreationInfos = SubstationCreationInfos.builder() - .equipmentId("substationId") - .country(Country.FR) - .build(); - LoadCreationInfos loadCreationInfos = LoadCreationInfos.builder() - .equipmentId("load1") - .equipmentName("loadName") - .build(); - return networkModificationRepository.saveModificationInfos(groupUuid, List.of(switchStatusModificationInfos, substationCreationInfos, loadCreationInfos)); - } -} diff --git a/src/test/java/org/gridsuite/modification/server/service/BuildTest.java b/src/test/java/org/gridsuite/modification/server/service/BuildTest.java index bd6b8150c..e5fe4e561 100644 --- a/src/test/java/org/gridsuite/modification/server/service/BuildTest.java +++ b/src/test/java/org/gridsuite/modification/server/service/BuildTest.java @@ -24,12 +24,7 @@ import org.gridsuite.modification.server.ContextConfigurationWithTestChannel; import org.gridsuite.modification.TapChangerType; import org.gridsuite.modification.dto.*; -import org.gridsuite.modification.server.dto.BuildInfos; -import org.gridsuite.modification.server.dto.NetworkInfos; -import org.gridsuite.modification.server.dto.NetworkModificationResult; -import org.gridsuite.modification.server.dto.ReportInfos; -import org.gridsuite.modification.server.dto.SubstationInfos; -import org.gridsuite.modification.server.dto.VoltageLevelInfos; +import org.gridsuite.modification.server.dto.*; import org.gridsuite.modification.server.dto.elasticsearch.EquipmentInfos; import org.gridsuite.modification.server.dto.elasticsearch.TombstonedEquipmentInfos; import org.gridsuite.modification.server.elasticsearch.EquipmentInfosRepository; @@ -934,14 +929,19 @@ void testApplyModificationWithErrors(final MockWebServer server) { assertTrue(TestUtils.getRequestsDone(1, server).stream().anyMatch(r -> r.matches(String.format("/v1/reports/%s", reportUuid)))); // Incremental mode : No error send with exception - Optional networkModificationResult2 = networkModificationService.createNetworkModification(TEST_NETWORK_ID, variantId, groupUuid, new ReportInfos(reportUuid, reporterId), loadCreationInfos); - assertTrue(networkModificationResult2.isPresent()); + ModificationApplicationContext applicationContext = new ModificationApplicationContext(TEST_NETWORK_ID, variantId, reportUuid, reporterId); + List> networkModificationResult2 = networkModificationService.createNetworkModification(groupUuid, loadCreationInfos, List.of(applicationContext)); + assertEquals(1, networkModificationResult2.size()); + assertTrue(networkModificationResult2.get(0).isPresent()); testEmptyImpactsWithErrors(networkModificationResult); assertTrue(TestUtils.getRequestsDone(1, server).stream().anyMatch(r -> r.matches(String.format("/v1/reports/%s", reportUuid)))); testNetworkModificationsCount(groupUuid, 1); // Save mode only (variant does not exist) : No log and no error send with exception - assertTrue(networkModificationService.createNetworkModification(TEST_NETWORK_ID, UUID.randomUUID().toString(), groupUuid, new ReportInfos(reportUuid, reporterId), loadCreationInfos).isEmpty()); + applicationContext = new ModificationApplicationContext(TEST_NETWORK_ID, UUID.randomUUID().toString(), reportUuid, reporterId); + networkModificationResult2 = networkModificationService.createNetworkModification(groupUuid, loadCreationInfos, List.of(applicationContext)); + assertEquals(1, networkModificationResult2.size()); + assertTrue(networkModificationResult2.get(0).isEmpty()); testNetworkModificationsCount(groupUuid, 2); }