diff --git a/src/main/java/org/gridsuite/modification/server/CompositeController.java b/src/main/java/org/gridsuite/modification/server/CompositeController.java index 768fc5e16..d2971bb9b 100644 --- a/src/main/java/org/gridsuite/modification/server/CompositeController.java +++ b/src/main/java/org/gridsuite/modification/server/CompositeController.java @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import org.gridsuite.modification.dto.ModificationInfos; +import org.gridsuite.modification.server.dto.CompositesToBeInserted; import org.gridsuite.modification.server.dto.ModificationApplicationContext; import org.gridsuite.modification.server.dto.NetworkModificationsResult; import org.gridsuite.modification.server.service.NetworkModificationService; @@ -50,7 +51,7 @@ public CompositeController(NetworkModificationService networkModificationService public CompletableFuture> insertCompositeModifications( @Parameter(description = "updated group UUID, where modifications are inserted") @PathVariable("groupUuid") UUID targetGroupUuid, @Parameter(description = "Insertion method", required = true) @RequestParam(value = "action") CompositeModificationAction action, - @RequestBody Pair>, List> modificationContextInfos) { + @RequestBody Pair, List> modificationContextInfos) { return switch (action) { case SPLIT -> networkModificationService.splitCompositeModifications( targetGroupUuid, diff --git a/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java b/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java index 9c4378dc6..30daa058c 100644 --- a/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java +++ b/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java @@ -244,6 +244,39 @@ public ResponseEntity stashNetworkModifications( return ResponseEntity.ok().build(); } + /** + * filters out the netmods which are not references and returns the references data as : + * referenced element uuid -> container of the reference (uuid of the composite if there is one, null if it is at the root level) + */ + @GetMapping(value = "/references", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "fetch references data of the network modifications") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The references data were returned")}) + public ResponseEntity> getReferencesData( + @Parameter(description = "Network modification UUIDs") @RequestParam("uuids") List networkModificationUuids) { + Map referencesData = networkModificationService.getReferencesData(networkModificationUuids); + return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON) + .body(referencesData); + } + + /** + * filters out the netmods which are not references and returns the references data as : + * referenced element uuid -> container of the reference (uuid of the composite if there is one, null if it is at the root level) + */ + @GetMapping(value = "/groups/{groupUuid}/references", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Fetches references data of all the network modifications in a group, including in the composites' submodifications") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The references data were returned")}) + public ResponseEntity> getAllReferencesDataFromGroup( + @Parameter(description = "Group UUID") @PathVariable("groupUuid") UUID groupUuid) { + // TODO GRD-4785 : for now shared modification are only at the root level and can't be inside composites, + // but when it will be the case a specific function will have to be done in order to fetch recursively all the references inside the composites and only return uuids + List netModUuids = networkModificationService.getNetworkModifications(groupUuid, true, false, false) + .stream().map(ModificationInfos::getUuid) + .toList(); + Map referencesData = networkModificationService.getReferencesData(netModUuids); + return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON) + .body(referencesData); + } + @PutMapping(value = "/network-modifications", produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Updates the metadata of network modifications") @ApiResponse(responseCode = "200", description = "The metadata of the network modifications has been successfully updated") diff --git a/src/main/java/org/gridsuite/modification/server/dto/CompositesToBeInserted.java b/src/main/java/org/gridsuite/modification/server/dto/CompositesToBeInserted.java new file mode 100644 index 000000000..8396644b6 --- /dev/null +++ b/src/main/java/org/gridsuite/modification/server/dto/CompositesToBeInserted.java @@ -0,0 +1,14 @@ +/* + Copyright (c) 2026, RTE (http://www.rte-france.com) + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.modification.server.dto; + +import java.util.UUID; + +/** + * @author Mathieu Deharbe + */ +public record CompositesToBeInserted(UUID id, String name, boolean isShared) { } diff --git a/src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java b/src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java index d1b07bfac..f2bd59062 100644 --- a/src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java +++ b/src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java @@ -18,6 +18,7 @@ import org.gridsuite.modification.dto.tabular.TabularBaseInfos; import org.gridsuite.modification.dto.tabular.TabularCreationInfos; import org.gridsuite.modification.dto.tabular.TabularModificationInfos; +import org.gridsuite.modification.server.dto.CompositesToBeInserted; import org.gridsuite.modification.server.dto.ModificationMetadata; import org.gridsuite.modification.server.elasticsearch.ModificationApplicationInfosService; import org.gridsuite.modification.server.entities.CompositeModificationEntity; @@ -29,7 +30,6 @@ import org.gridsuite.modification.server.entities.tabular.TabularPropertyEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.data.util.Pair; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -710,6 +710,28 @@ private List getUnstashedModificationsInfosNonTransactional(U return getModificationEntityStream(groupUuid).filter(m -> !m.getStashed()).map(this::toModificationsInfosOptimized).toList(); } + /** + * @return elementUuid of the shared modification -> Uuid of the composite containing the reference, null if the modification reference is at the root level + */ + @Transactional + public Map getReferencesData(@NonNull List modificationUuids) { + Map references = new HashMap<>(); + + List modificationEntities = this.modificationRepository.findAllByIdIn(modificationUuids); + + modificationEntities.stream() + // TODO GRD-4785 : for now shared modification are only at the root level and can't be inside composites, so the composite uuid is set to null + // but when it will be the case a specific function will have to be done in order to fetch the composite containing the modificationReference (if there is one) + .filter(modificationEntity -> Boolean.FALSE.equals(modificationEntity.getStashed())) + .forEach(modificationEntity -> { + if (modificationEntity instanceof ModificationReferenceEntity modificationReference) { + references.putIfAbsent(modificationReference.getReferenceId(), null); + } + }); + + return references; + } + @Transactional public void stashNetworkModifications(@NonNull List modificationUuids, int stashedModificationCount) { int stashModificationOrder = -stashedModificationCount - 1; @@ -937,20 +959,35 @@ public List extractModificationsFromCompositesAndSave(@NonNul @Transactional public List insertCompositeModifications( @NonNull UUID targetGroupUuid, - @NonNull List> compositesUuidName) { - List compositeUuids = compositesUuidName.stream().map(Pair::getFirst).toList(); + @NonNull List compositesToBeInserted) { + List compositeUuids = compositesToBeInserted.stream().map(CompositesToBeInserted::id).toList(); List newCompositeModifications = new ArrayList<>(); List modificationInfos = getModificationsInfosNonTransactional(compositeUuids); - // apply the new composite name to the corresponding composite modifications - for (Pair compositeUuidName : compositesUuidName) { - CompositeModificationInfos newCompositeModification = (CompositeModificationInfos) modificationInfos.stream() - .filter(modif -> modif.getUuid().equals(compositeUuidName.getFirst())) - .findFirst().orElse(null); - if (newCompositeModification != null) { - newCompositeModification.setName(compositeUuidName.getSecond()); - newCompositeModifications.add(newCompositeModification); + for (CompositesToBeInserted compositeToBeInserted : compositesToBeInserted) { + if (compositeToBeInserted.isShared()) { + CompositeModificationInfos referencedCompositeModification = (CompositeModificationInfos) modificationInfos.stream() + .filter(modif -> modif.getUuid().equals(compositeToBeInserted.id())) + .findFirst().orElse(null); + if (referencedCompositeModification != null) { + referencedCompositeModification.setName(compositeToBeInserted.name()); + ModificationReferenceInfos newModificationReference = ModificationReferenceInfos.builder() + .referenceId(compositeToBeInserted.id()) + .referenceType(ModificationReferenceInfos.Type.BASIC) + .referenceInfos(referencedCompositeModification) + .build(); + newCompositeModifications.add(newModificationReference); + } } else { - LOGGER.error("Could not find composite modification with uuid {} to apply its name {}", compositeUuidName.getFirst(), compositeUuidName.getSecond()); + // apply the new composite name to the corresponding composite modifications + CompositeModificationInfos newCompositeModification = (CompositeModificationInfos) modificationInfos.stream() + .filter(modif -> modif.getUuid().equals(compositeToBeInserted.id())) + .findFirst().orElse(null); + if (newCompositeModification != null) { + newCompositeModification.setName(compositeToBeInserted.name()); + newCompositeModifications.add(newCompositeModification); + } else { + LOGGER.error("Could not find composite modification with uuid {} to apply its name {}", compositeToBeInserted.id(), compositeToBeInserted.name()); + } } } List newEntities = saveModificationInfosNonTransactional(targetGroupUuid, newCompositeModifications); 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 6bceee191..a94a027c0 100644 --- a/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java @@ -27,6 +27,7 @@ import org.gridsuite.modification.dto.ModificationInfos; import org.gridsuite.modification.server.NetworkModificationServerException; import org.gridsuite.modification.server.dto.*; +import org.gridsuite.modification.server.dto.CompositesToBeInserted; import org.gridsuite.modification.server.dto.elasticsearch.ModificationApplicationInfos; import org.gridsuite.modification.server.elasticsearch.EquipmentInfosService; import org.gridsuite.modification.server.elasticsearch.ModificationApplicationInfosService; @@ -269,6 +270,11 @@ public void updateNetworkModificationMetadata(@NonNull List modificationUu networkModificationRepository.updateNetworkModificationMetadata(modificationUuids, metadata); } + @Transactional + public Map getReferencesData(@NonNull List modificationUuids) { + return networkModificationRepository.getReferencesData(modificationUuids); + } + @Transactional public void stashNetworkModifications(UUID groupUuid, @NonNull List modificationUuids) { for (UUID modificationUuid : modificationUuids) { @@ -487,8 +493,8 @@ public CompletableFuture duplicateModifications(@Non */ public CompletableFuture splitCompositeModifications( @NonNull UUID targetGroupUuid, - @NonNull Pair>, List> modificationContextInfos) { - List compositesUuids = modificationContextInfos.getFirst().stream().map(Pair::getFirst).toList(); + @NonNull Pair, List> modificationContextInfos) { + List compositesUuids = modificationContextInfos.getFirst().stream().map(CompositesToBeInserted::id).toList(); List modifications = networkModificationRepository.extractModificationsFromCompositesAndSave(targetGroupUuid, compositesUuids); List ids = modifications.stream().map(ModificationInfos::getUuid).toList(); return applyModifications(targetGroupUuid, modifications, modificationContextInfos.getSecond()).thenApply(result -> @@ -497,7 +503,7 @@ public CompletableFuture splitCompositeModifications public CompletableFuture insertCompositeModifications( @NonNull UUID targetGroupUuid, - @NonNull Pair>, List> modificationContextInfos) { + @NonNull Pair, List> modificationContextInfos) { List modifications = networkModificationRepository.insertCompositeModifications( targetGroupUuid, modificationContextInfos.getFirst()); List ids = modifications.stream().map(ModificationInfos::getUuid).toList(); diff --git a/src/test/java/org/gridsuite/modification/server/CompositeControllerTest.java b/src/test/java/org/gridsuite/modification/server/CompositeControllerTest.java index 3a9e5c465..ec95ad7c5 100644 --- a/src/test/java/org/gridsuite/modification/server/CompositeControllerTest.java +++ b/src/test/java/org/gridsuite/modification/server/CompositeControllerTest.java @@ -18,6 +18,8 @@ import org.gridsuite.modification.dto.CompositeModificationInfos; import org.gridsuite.modification.dto.EquipmentAttributeModificationInfos; import org.gridsuite.modification.dto.ModificationInfos; +import org.gridsuite.modification.dto.ModificationReferenceInfos; +import org.gridsuite.modification.server.dto.CompositesToBeInserted; import org.gridsuite.modification.server.dto.NetworkModificationResult; import org.gridsuite.modification.server.dto.NetworkModificationsResult; import org.gridsuite.modification.server.entities.CompositeModificationEntity; @@ -34,7 +36,6 @@ 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.data.util.Pair; import org.springframework.http.MediaType; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; @@ -166,8 +167,8 @@ void testSplit() throws Exception { checkCompositeModificationContent(compositeModificationContent); // Insert the composite modification in the group - final String bodyJson = getJsonBodyModificationCompositeInfos( - List.of(Pair.of(compositeModificationUuid, "random name"))); + final String bodyJson = getJsonBodyModificationCompositeToBeInserted( + List.of(new CompositesToBeInserted(compositeModificationUuid, "random name", false))); mvcResult = runRequestAsync( mockMvc, put(URI_COMPOSITE_NETWORK_MODIF_BASE + "/groups/" + TEST_GROUP_ID + "?action=SPLIT") @@ -202,8 +203,8 @@ void testInsert() throws Exception { assertEquals(modificationsNumber, modificationInfosList.size()); // Insert the composite modification in the group - final String bodyJson = getJsonBodyModificationCompositeInfos( - List.of(Pair.of(compositeModificationUuid, "random name"))); + final String bodyJson = getJsonBodyModificationCompositeToBeInserted( + List.of(new CompositesToBeInserted(compositeModificationUuid, "random name", false))); // insert the same composite modification inside as a complete composite, not split into regular network modifications mvcResult = runRequestAsync( @@ -220,6 +221,48 @@ void testInsert() throws Exception { checkCompositeModificationContent(insertedComposite.getModificationsInfos()); } + @Test + void testInsertSharedComposite() throws Exception { + int modificationsNumber = 2; + List modificationList = createSomeSwitchModifications(TEST_GROUP_ID, modificationsNumber); + + MvcResult mvcResult = mockMvc.perform(post(URI_COMPOSITE_NETWORK_MODIF_BASE) + .content(mapper.writeValueAsString(modificationList.stream().map(ModificationInfos::getUuid).toList())) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + UUID compositeModificationUuid = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); + + String bodyJson = getJsonBodyModificationCompositeToBeInserted( + List.of(new CompositesToBeInserted(compositeModificationUuid, "shared composite", true))); + + mvcResult = runRequestAsync( + mockMvc, + put(URI_COMPOSITE_NETWORK_MODIF_BASE + "/groups/" + TEST_GROUP_ID + "?action=INSERT") + .content(bodyJson) + .contentType(MediaType.APPLICATION_JSON), + status().isOk()); + + assertApplicationStatusOK(mvcResult); + + List newModificationList = modificationRepository.getModifications(TEST_GROUP_ID, false, true); + assertEquals(modificationsNumber + 1, newModificationList.size()); + + ModificationReferenceInfos insertedReference = assertInstanceOf( + ModificationReferenceInfos.class, + newModificationList.getLast() + ); + assertEquals(compositeModificationUuid, insertedReference.getReferenceId()); + assertEquals(ModificationReferenceInfos.Type.BASIC, insertedReference.getReferenceType()); + + CompositeModificationInfos referencedComposite = assertInstanceOf( + CompositeModificationInfos.class, + insertedReference.getReferenceInfos() + ); + assertEquals(compositeModificationUuid, referencedComposite.getUuid()); + checkCompositeModificationContent(referencedComposite.getModificationsInfos()); + } + private static void checkCompositeModificationContent(List compositeModificationContent) { assertEquals("open", ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentAttributeName()); assertEquals(Boolean.TRUE, ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentAttributeValue()); @@ -246,7 +289,7 @@ private List createSomeSwitchModifications(UUID groupId, int return modificationList; } - private String getJsonBodyModificationCompositeInfos(List> modifs) throws JsonProcessingException { + private String getJsonBodyModificationCompositeToBeInserted(List modifs) throws JsonProcessingException { return TestUtils.getJsonBodyModificationCompositeInfos(modifs, TEST_NETWORK_ID, VARIANT_ID); } @@ -398,7 +441,7 @@ void testMoveSubModificationWithinComposite() throws Exception { // Move the first sub-modification to the end (no beforeUuid = append) // was [0,1,2] → [1,2,0] mockMvc.perform(put(URI_COMPOSITE_NETWORK_MODIF_BASE + "/groups/{groupUuid}/sub-modifications/{modificationUuid}", - TEST_GROUP_ID, subUuids.get(0)) + TEST_GROUP_ID, subUuids.getFirst()) .queryParam("sourceCompositeUuid", compositeUuid.toString()) .queryParam("targetCompositeUuid", compositeUuid.toString())) .andExpect(status().isOk()); @@ -445,7 +488,8 @@ void testMoveSubModificationFromCompositeToRoot() throws Exception { runRequestAsync(mockMvc, put(URI_COMPOSITE_NETWORK_MODIF_BASE + "/groups/{groupUuid}?action=INSERT", TEST_GROUP_ID) - .content(getJsonBodyModificationCompositeInfos(List.of(Pair.of(compositeUuid, "composite")))) + .content(getJsonBodyModificationCompositeToBeInserted( + List.of(new CompositesToBeInserted(compositeUuid, "composite", false)))) .contentType(MediaType.APPLICATION_JSON), status().isOk()); @@ -460,7 +504,7 @@ void testMoveSubModificationFromCompositeToRoot() throws Exception { int rootSizeBefore = modificationRepository.getModifications(TEST_GROUP_ID, true, true).size(); // Move first sub-modification from composite to root level (no targetCompositeUuid) - UUID movingUuid = actualSubUuids.get(0); + UUID movingUuid = actualSubUuids.getFirst(); mockMvc.perform(put(URI_COMPOSITE_NETWORK_MODIF_BASE + "/groups/{groupUuid}/sub-modifications/{modificationUuid}", TEST_GROUP_ID, movingUuid) .queryParam("sourceCompositeUuid", compositeUuid.toString())) @@ -472,7 +516,7 @@ void testMoveSubModificationFromCompositeToRoot() throws Exception { .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(), new TypeReference<>() { }); assertEquals(1, resultMap.get(compositeUuid).size()); - assertEquals(actualSubUuids.get(1), resultMap.get(compositeUuid).get(0).getUuid()); + assertEquals(actualSubUuids.get(1), resultMap.get(compositeUuid).getFirst().getUuid()); // Root group should have one more modification assertEquals(rootSizeBefore + 1, modificationRepository.getModifications(TEST_GROUP_ID, true, true).size()); @@ -596,7 +640,7 @@ void testExpandToLeafUuidsNestedComposites() throws Exception { assertEquals(2, actualInnerSubUuids.size()); List outerLeafs = createSomeSwitchModifications(TEST_GROUP2_ID, 1); - UUID leaf3RootUuid = outerLeafs.get(0).getUuid(); + UUID leaf3RootUuid = outerLeafs.getFirst().getUuid(); mvcResult = mockMvc.perform(post(URI_COMPOSITE_NETWORK_MODIF_BASE) .content(mapper.writeValueAsString(List.of(innerCompositeUuid, leaf3RootUuid))).contentType(MediaType.APPLICATION_JSON)) @@ -657,7 +701,7 @@ void testMoveSubModificationFromRootToComposite() throws Exception { runRequestAsync(mockMvc, put(URI_COMPOSITE_NETWORK_MODIF_BASE + "/groups/{groupUuid}?action=INSERT", TEST_GROUP_ID) - .content(getJsonBodyModificationCompositeInfos(List.of(Pair.of(compositeUuid, "composite")))) + .content(getJsonBodyModificationCompositeToBeInserted(List.of(new CompositesToBeInserted(compositeUuid, "composite", false)))) .contentType(MediaType.APPLICATION_JSON), status().isOk()); @@ -720,7 +764,7 @@ void testMoveSubModificationCycleDetection() throws Exception { UUID composite1Uuid = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); List extraLeafs = createSomeSwitchModifications(TEST_GROUP2_ID, 1); - UUID leaf4Uuid = extraLeafs.get(0).getUuid(); + UUID leaf4Uuid = extraLeafs.getFirst().getUuid(); mvcResult = mockMvc.perform(post(URI_COMPOSITE_NETWORK_MODIF_BASE) .content(mapper.writeValueAsString(List.of(composite1Uuid, leaf4Uuid))).contentType(MediaType.APPLICATION_JSON)) diff --git a/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java b/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java index 598b8e9e9..abaf34ed2 100644 --- a/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java +++ b/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java @@ -177,8 +177,8 @@ private boolean existTombstonedEquipmentInfos(String equipmentId, UUID networkUu private void assertApplicationStatusOK(MvcResult mvcResult) throws Exception { NetworkModificationsResult networkModificationsResult = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); assertEquals(1, networkModificationsResult.modificationResults().size()); - assertTrue(networkModificationsResult.modificationResults().get(0).isPresent()); - assertNotEquals(NetworkModificationResult.ApplicationStatus.WITH_ERRORS, networkModificationsResult.modificationResults().get(0).get().getApplicationStatus()); + assertTrue(networkModificationsResult.modificationResults().getFirst().isPresent()); + assertNotEquals(NetworkModificationResult.ApplicationStatus.WITH_ERRORS, networkModificationsResult.modificationResults().getFirst().get().getApplicationStatus()); } private String getJsonBody(List uuids, String variantId) throws JsonProcessingException { @@ -371,7 +371,7 @@ void testRestoreNetworkModifications() throws Exception { List modifications = modificationRepository.getModifications(TEST_GROUP_ID, true, true, false); assertEquals(1, modifications.size()); - String uuidString = modifications.get(0).getUuid().toString(); + String uuidString = modifications.getFirst().getUuid().toString(); mockMvc.perform(put(URI_NETWORK_MODIF_BASE) .queryParam("groupUuid", TEST_GROUP_ID.toString()) .queryParam("uuids", uuidString) @@ -397,7 +397,7 @@ void testStashNetworkModifications() throws Exception { List modifications = modificationRepository.getModifications(TEST_GROUP_ID, false, true); assertEquals(1, modifications.size()); - String uuidString = modifications.get(0).getUuid().toString(); + String uuidString = modifications.getFirst().getUuid().toString(); mockMvc.perform(put(URI_NETWORK_MODIF_BASE) .queryParam("groupUuid", TEST_GROUP_ID.toString()) .queryParam("uuids", uuidString) @@ -424,7 +424,7 @@ void testDisableNetworkModifications() throws Exception { List modifications = modificationRepository.getModifications(TEST_GROUP_ID, true, true); assertEquals(1, modifications.size()); - assertEquals(true, modifications.get(0).getActivated()); + assertEquals(true, modifications.getFirst().getActivated()); ModificationInfos metadata = new ModificationInfos(); metadata.setType(LINE_MODIFICATION); @@ -436,7 +436,7 @@ void testDisableNetworkModifications() throws Exception { .content(mapper.writeValueAsString(metadata)) .contentType(MediaType.APPLICATION_JSON) ).andExpect(status().isOk()); - assertEquals(false, modificationRepository.getModifications(TEST_GROUP_ID, true, true).get(0).getActivated()); + assertEquals(false, modificationRepository.getModifications(TEST_GROUP_ID, true, true).getFirst().getActivated()); } @Test @@ -510,7 +510,7 @@ void testDeleteModification() throws Exception { List modifications = modificationRepository.getModifications(TEST_GROUP_ID, false, true); assertEquals(1, modifications.size()); - String uuidString = modifications.get(0).getUuid().toString(); + String uuidString = modifications.getFirst().getUuid().toString(); mockMvc.perform(delete(URI_NETWORK_MODIF_BASE) .queryParam("groupUuid", UUID.randomUUID().toString()) .queryParam("uuids", uuidString)) @@ -920,8 +920,8 @@ void testMoveModificationBetweenTwoGroups() throws Exception { // incremental build: deletion impacts expected, all related to the moved load deletion (dealing with "s1" substation) NetworkModificationsResult networkModificationsResult = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); assertEquals(1, networkModificationsResult.modificationResults().size()); - assertTrue(networkModificationsResult.modificationResults().get(0).isPresent()); - networkModificationsResult.modificationResults().get(0).get().getNetworkImpacts().forEach(i -> { + assertTrue(networkModificationsResult.modificationResults().getFirst().isPresent()); + networkModificationsResult.modificationResults().getFirst().get().getNetworkImpacts().forEach(i -> { assertTrue(i.isSimple()); SimpleElementImpact simpleImpact = (SimpleElementImpact) i; assertEquals(Set.of(substationS1), simpleImpact.getSubstationIds()); @@ -953,7 +953,7 @@ void testMoveModificationWithUnexistingId() throws Exception { // try to move an unexisting modification before [0]: no error, no change List movingModificationUuidList = List.of(UUID.randomUUID()); String bodyJson = getJsonBody(movingModificationUuidList, NetworkCreation.VARIANT_ID); - String url = "/v1/groups/" + TEST_GROUP_ID + "?action=MOVE" + "&originGroupUuid=" + TEST_GROUP_ID + "&before=" + modificationUuidList.get(0); + String url = "/v1/groups/" + TEST_GROUP_ID + "?action=MOVE" + "&originGroupUuid=" + TEST_GROUP_ID + "&before=" + modificationUuidList.getFirst(); mockMvc.perform(put(url).content(bodyJson) .contentType(MediaType.APPLICATION_JSON)) @@ -1042,7 +1042,7 @@ void testDuplicateModificationGroup() throws Exception { List modifications = modificationRepository.getModifications(TEST_GROUP_ID, true, true, false); assertEquals(5, modifications.size()); //stash the first modification - String uuidString = modifications.get(0).getUuid().toString(); + String uuidString = modifications.getFirst().getUuid().toString(); mockMvc.perform(put(URI_NETWORK_MODIF_BASE) .queryParam("groupUuid", TEST_GROUP_ID.toString()) @@ -1542,7 +1542,7 @@ void testCreateVoltageInitModification() throws Exception { List modificationsInfos2 = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); assertEquals(1, modificationsInfos2.size()); - assertThat(modificationsInfos2.get(0)).recursivelyEquals(modificationsInfos1); + assertThat(modificationsInfos2.getFirst()).recursivelyEquals(modificationsInfos1); } @Test @@ -1561,7 +1561,7 @@ void testDeleteStashedNetworkModifications() throws Exception { List modifications = modificationRepository.getModifications(TEST_GROUP_ID, true, true); assertEquals(1, modifications.size()); - String uuidString = modifications.get(0).getUuid().toString(); + String uuidString = modifications.getFirst().getUuid().toString(); mockMvc.perform(put(URI_NETWORK_MODIF_BASE) .queryParam("groupUuid", TEST_GROUP_ID.toString()) .queryParam("uuids", uuidString) @@ -1597,22 +1597,22 @@ void testGetModificationsCount() throws Exception { void testMetadata() throws Exception { // create a single switch attribute modification in a group List modificationList = createSomeSwitchModifications(TEST_GROUP_ID, 1); - UUID switchModificationId = modificationList.get(0).getUuid(); + UUID switchModificationId = modificationList.getFirst().getUuid(); MvcResult mvcResult = mockMvc.perform(get(URI_NETWORK_MODIF_BASE + "/metadata?ids={id}", switchModificationId) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()).andReturn(); List metadata = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); assertEquals(1, metadata.size()); - assertEquals(switchModificationId, metadata.get(0).getId()); - assertEquals(EQUIPMENT_ATTRIBUTE_MODIFICATION, metadata.get(0).getType()); + assertEquals(switchModificationId, metadata.getFirst().getId()); + assertEquals(EQUIPMENT_ATTRIBUTE_MODIFICATION, metadata.getFirst().getType()); } @Test void testStandaloneDeletionError() throws Exception { // create a single switch attribute modification in a group List modificationList = createSomeSwitchModifications(TEST_GROUP_ID, 1); - UUID switchModificationId = modificationList.get(0).getUuid(); + UUID switchModificationId = modificationList.getFirst().getUuid(); // Try to delete this modification without its group: not allowed mockMvc.perform(delete(URI_NETWORK_MODIF_BASE) @@ -1628,7 +1628,7 @@ void testStandaloneDeletionError() throws Exception { void testVerifyModifications() throws Exception { // create a single switch attribute modification in a group List modificationList = createSomeSwitchModifications(TEST_GROUP_ID, 1); - UUID switchModificationId = modificationList.get(0).getUuid(); + UUID switchModificationId = modificationList.getFirst().getUuid(); createSomeSwitchModifications(TEST_GROUP2_ID, 1); @@ -1819,7 +1819,7 @@ private UUID createComposite(List modificationUuids) throws Exception { /** Inserts a COPY of a standalone composite at the end of the group's root list. */ private void insertCompositeIntoGroup(UUID groupId, UUID compositeUuid, String name) throws Exception { String body = TestUtils.getJsonBodyModificationCompositeInfos( - List.of(org.springframework.data.util.Pair.of(compositeUuid, name)), + List.of(new CompositesToBeInserted(compositeUuid, name, false)), TEST_NETWORK_ID, NetworkCreation.VARIANT_ID); runRequestAsync(mockMvc, put("/v1/network-composite-modifications/groups/" + groupId + "?action=INSERT") @@ -1910,4 +1910,103 @@ void testMoveCompositeAndSubModificationInterGroup() throws Exception { // destination receives C(intact), D, extracted E1 assertEquals(l.cSubs(), fetchCompositeSubUuids(l.c())); } + + @Test + void testGetReferencesData() throws Exception { + // Create a non-reference modification: it must be ignored by getReferencesData + List switchModifications = createSomeSwitchModifications(TEST_GROUP_ID, 1); + UUID nonReferenceModificationUuid = switchModifications.getFirst().getUuid(); + + // Create a referenced modification, not owned by the tested group + ModificationInfos referencedLoadModificationInfo = ModificationCreation.getCreationLoad("v1", "idLoad", "nameLoad", "1.1", LoadType.UNDEFINED); + referencedLoadModificationInfo = modificationRepository.saveModifications(UUID.randomUUID(), List.of(ModificationEntity.fromDTO(referencedLoadModificationInfo))).getFirst(); + + // Create an active reference to this modification + ModificationInfos activeReferenceInfo = ModificationReferenceInfos.builder() + .referenceType(ModificationReferenceInfos.Type.BASIC) + .referenceId(referencedLoadModificationInfo.getUuid()) + .referenceInfos(referencedLoadModificationInfo) + .stashed(false) + .build(); + activeReferenceInfo = modificationRepository.saveModifications(TEST_GROUP_ID, List.of(ModificationEntity.fromDTO(activeReferenceInfo))).getFirst(); + + // Create a stashed reference: it must also be ignored by getReferencesData + ModificationInfos stashedReferenceInfo = ModificationReferenceInfos.builder() + .referenceType(ModificationReferenceInfos.Type.BASIC) + .referenceId(referencedLoadModificationInfo.getUuid()) + .referenceInfos(referencedLoadModificationInfo) + .stashed(true) + .build(); + stashedReferenceInfo = modificationRepository.saveModifications(TEST_GROUP_ID, List.of(ModificationEntity.fromDTO(stashedReferenceInfo))).getFirst(); + + MvcResult mvcResult = mockMvc.perform(get("/v1/references") + .queryParam("uuids", + activeReferenceInfo.getUuid().toString(), + nonReferenceModificationUuid.toString(), + stashedReferenceInfo.getUuid().toString()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll(status().isOk(), content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Map referencesData = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); + + assertEquals(1, referencesData.size()); + assertTrue(referencesData.containsKey(referencedLoadModificationInfo.getUuid())); + assertNull(referencesData.get(referencedLoadModificationInfo.getUuid())); + } + + @Test + void testGetAllReferencesDataFromGroup() throws Exception { + // Create a non-reference modification in the group: it must be ignored by getAllReferencesDataFromGroup + createSomeSwitchModifications(TEST_GROUP_ID, 1); + + // Create a referenced modification, not owned by the tested group + ModificationInfos referencedLoadModificationInfo = ModificationCreation.getCreationLoad("v1", "idLoad", "nameLoad", "1.1", LoadType.UNDEFINED); + referencedLoadModificationInfo = modificationRepository.saveModifications(UUID.randomUUID(), List.of(ModificationEntity.fromDTO(referencedLoadModificationInfo))).getFirst(); + + // Create an active reference in the tested group: it must be returned + ModificationInfos activeReferenceInfo = ModificationReferenceInfos.builder() + .referenceType(ModificationReferenceInfos.Type.BASIC) + .referenceId(referencedLoadModificationInfo.getUuid()) + .referenceInfos(referencedLoadModificationInfo) + .stashed(false) + .build(); + modificationRepository.saveModifications(TEST_GROUP_ID, List.of(ModificationEntity.fromDTO(activeReferenceInfo))); + + // Create a stashed reference in the tested group: it must be ignored + ModificationInfos stashedReferenceInfo = ModificationReferenceInfos.builder() + .referenceType(ModificationReferenceInfos.Type.BASIC) + .referenceId(referencedLoadModificationInfo.getUuid()) + .referenceInfos(referencedLoadModificationInfo) + .stashed(true) + .build(); + modificationRepository.saveModifications(TEST_GROUP_ID, List.of(ModificationEntity.fromDTO(stashedReferenceInfo))); + + // Create an active reference in another group: it must not be returned for TEST_GROUP_ID + ModificationInfos otherGroupReferencedLoadModificationInfo = ModificationCreation.getCreationLoad("v1", "idLoadOther", "nameLoadOther", "1.1", LoadType.UNDEFINED); + otherGroupReferencedLoadModificationInfo = modificationRepository.saveModifications( + UUID.randomUUID(), + List.of(ModificationEntity.fromDTO(otherGroupReferencedLoadModificationInfo)) + ).getFirst(); + + ModificationInfos otherGroupReferenceInfo = ModificationReferenceInfos.builder() + .referenceType(ModificationReferenceInfos.Type.BASIC) + .referenceId(otherGroupReferencedLoadModificationInfo.getUuid()) + .referenceInfos(otherGroupReferencedLoadModificationInfo) + .stashed(false) + .build(); + modificationRepository.saveModifications(TEST_GROUP2_ID, List.of(ModificationEntity.fromDTO(otherGroupReferenceInfo))); + + MvcResult mvcResult = mockMvc.perform(get("/v1/groups/{groupUuid}/references", TEST_GROUP_ID) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll(status().isOk(), content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + + Map referencesData = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); + + assertEquals(1, referencesData.size()); + assertTrue(referencesData.containsKey(referencedLoadModificationInfo.getUuid())); + assertNull(referencesData.get(referencedLoadModificationInfo.getUuid())); + assertFalse(referencesData.containsKey(otherGroupReferencedLoadModificationInfo.getUuid())); + } } diff --git a/src/test/java/org/gridsuite/modification/server/service/ModificationIndexationTest.java b/src/test/java/org/gridsuite/modification/server/service/ModificationIndexationTest.java index 92608fe6f..2d9cf5a3d 100644 --- a/src/test/java/org/gridsuite/modification/server/service/ModificationIndexationTest.java +++ b/src/test/java/org/gridsuite/modification/server/service/ModificationIndexationTest.java @@ -308,8 +308,8 @@ void testInsertCompositeModifications() { Split this composite and insert the contained modifications to group 2, variant 2 */ UUID groupUuid2 = UUID.randomUUID(); - Pair>, List> modificationContextInfos = Pair.of( - List.of(Pair.of(compositeUuid, "")), + Pair, List> modificationContextInfos = Pair.of( + List.of(new CompositesToBeInserted(compositeUuid, "", false)), List.of(new ModificationApplicationContext(networkInfos.getNetworkUuuid(), variant2, UUID.randomUUID(), UUID.randomUUID())) ); NetworkModificationsResult modificationsResult = networkModificationService.splitCompositeModifications( diff --git a/src/test/java/org/gridsuite/modification/server/utils/TestUtils.java b/src/test/java/org/gridsuite/modification/server/utils/TestUtils.java index fe447feda..9e5b505b7 100644 --- a/src/test/java/org/gridsuite/modification/server/utils/TestUtils.java +++ b/src/test/java/org/gridsuite/modification/server/utils/TestUtils.java @@ -27,7 +27,6 @@ import org.junit.platform.commons.util.StringUtils; import org.mockito.ArgumentCaptor; import org.springframework.cloud.stream.binder.test.OutputDestination; -import org.springframework.data.util.Pair; import org.springframework.test.web.servlet.*; import java.io.IOException; @@ -230,7 +229,7 @@ public static String getJsonBody(List uuids, UUID networkUuid, String vari return createJsonPayload(uuids, networkUuid, variantId); } - public static String getJsonBodyModificationCompositeInfos(List> modifs, UUID networkUuid, String variantId) throws JsonProcessingException { + public static String getJsonBodyModificationCompositeInfos(List modifs, UUID networkUuid, String variantId) throws JsonProcessingException { return createJsonPayload(modifs, networkUuid, variantId); }