diff --git a/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationResult.java b/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationResult.java index 664a11e9c..0e7f8bd06 100644 --- a/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationResult.java +++ b/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationResult.java @@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Data; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.impacts.SimpleElementImpact; import java.util.List; @@ -18,6 +19,7 @@ /** * @author Slimane Amar + * @author Sylvain Bouzols */ @Builder @Data @@ -47,10 +49,12 @@ public ApplicationStatus max(ApplicationStatus other) { @Schema(description = "Network modification impacts") @Builder.Default - private List networkImpacts = List.of(); + private List networkImpacts = List.of(); public Set getImpactedSubstationsIds() { - return networkImpacts.stream().flatMap(impact -> impact.getSubstationIds().stream()).collect(Collectors.toCollection(TreeSet::new)); + return networkImpacts.stream() + .filter(impact -> impact.isSimple()) + .flatMap(impact -> ((SimpleElementImpact) impact).getSubstationIds().stream()) + .collect(Collectors.toCollection(TreeSet::new)); // using TreeSet to keep natural order } - } diff --git a/src/main/java/org/gridsuite/modification/server/impacts/AbstractBaseImpact.java b/src/main/java/org/gridsuite/modification/server/impacts/AbstractBaseImpact.java new file mode 100644 index 000000000..cdf93cd43 --- /dev/null +++ b/src/main/java/org/gridsuite/modification/server/impacts/AbstractBaseImpact.java @@ -0,0 +1,55 @@ +/** + Copyright (c) 2024, All partners of the iTesla project (http://www.itesla-project.eu/consortium) + 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.impacts; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.powsybl.iidm.network.IdentifiableType; + +import lombok.*; +import lombok.experimental.SuperBuilder; + +/** + * This class describes a base impact + * This is the base type of all network impacts + * + * @author Sylvain Bouzols + */ +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXISTING_PROPERTY, + property = "type", + visible = true +) +@JsonSubTypes({ + @JsonSubTypes.Type(value = SimpleElementImpact.class, name = "SIMPLE"), + @JsonSubTypes.Type(value = CollectionElementImpact.class, name = "COLLECTION") +}) +@SuperBuilder +@Data +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor +public abstract class AbstractBaseImpact { + + + public enum ImpactType { + SIMPLE, + COLLECTION + } + + @Setter(AccessLevel.NONE) + private ImpactType type; + + private IdentifiableType elementType; + + @JsonIgnore + public abstract boolean isSimple(); + + @JsonIgnore + public abstract boolean isCollection(); +} diff --git a/src/main/java/org/gridsuite/modification/server/impacts/CollectionElementImpact.java b/src/main/java/org/gridsuite/modification/server/impacts/CollectionElementImpact.java new file mode 100644 index 000000000..f496f15f1 --- /dev/null +++ b/src/main/java/org/gridsuite/modification/server/impacts/CollectionElementImpact.java @@ -0,0 +1,36 @@ +/** + Copyright (c) 2024, All partners of the iTesla project (http://www.itesla-project.eu/consortium) + 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.impacts; + +import lombok.*; +import lombok.experimental.SuperBuilder; + +/** + * This class describes a collection type network impact + * This type of network impact describes an impact on multiple items of the same IdentifiableType + * + * @author Sylvain Bouzols + */ +@SuperBuilder +@Data +@ToString(callSuper = true) +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class CollectionElementImpact extends AbstractBaseImpact { + @Override + public ImpactType getType() { + return ImpactType.COLLECTION; + } + + public boolean isSimple() { + return false; + } + + public boolean isCollection() { + return true; + } +} diff --git a/src/main/java/org/gridsuite/modification/server/impacts/SimpleElementImpact.java b/src/main/java/org/gridsuite/modification/server/impacts/SimpleElementImpact.java index 7e69afd19..15af46866 100644 --- a/src/main/java/org/gridsuite/modification/server/impacts/SimpleElementImpact.java +++ b/src/main/java/org/gridsuite/modification/server/impacts/SimpleElementImpact.java @@ -6,38 +6,67 @@ */ package org.gridsuite.modification.server.impacts; -import com.powsybl.iidm.network.IdentifiableType; import lombok.*; +import lombok.experimental.SuperBuilder; import java.util.Set; +import com.fasterxml.jackson.annotation.JsonIgnore; + /** * This class describes an element type network impact - * This type of network impact only describes an individual impacted item and the list of associated subtractions + * This type of network impact only describes an individual impacted item and the list of associated substations * * @author Slimane Amar + * @author Sylvain Bouzols */ -@AllArgsConstructor(access = AccessLevel.PRIVATE) -@Setter -@Getter -@Builder +@SuperBuilder +@Data +@ToString(callSuper = true) +@AllArgsConstructor @NoArgsConstructor -@EqualsAndHashCode(callSuper = false) -@ToString -public class SimpleElementImpact { +@EqualsAndHashCode(callSuper = true) +public class SimpleElementImpact extends AbstractBaseImpact { + public enum SimpleImpactType { CREATION, MODIFICATION, DELETION } - private SimpleImpactType impactType; + private SimpleImpactType simpleImpactType; /** The impacted element ID */ private String elementId; - private IdentifiableType elementType; - /** The impacted substations IDs */ private Set substationIds; + + @Override + public ImpactType getType() { + return ImpactType.SIMPLE; + } + + public boolean isSimple() { + return true; + } + + public boolean isCollection() { + return false; + } + + @JsonIgnore + public boolean isCreation() { + return getSimpleImpactType() == SimpleImpactType.CREATION; + } + + @JsonIgnore + public boolean isModification() { + return getSimpleImpactType() == SimpleImpactType.MODIFICATION; + } + + @JsonIgnore + public boolean isDeletion() { + return getSimpleImpactType() == SimpleImpactType.DELETION; + } } diff --git a/src/main/java/org/gridsuite/modification/server/modifications/NetworkModificationApplicator.java b/src/main/java/org/gridsuite/modification/server/modifications/NetworkModificationApplicator.java index 30d99d3a6..6acad6f44 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/NetworkModificationApplicator.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/NetworkModificationApplicator.java @@ -15,6 +15,7 @@ import com.powsybl.iidm.network.Network; import com.powsybl.network.store.client.NetworkStoreService; import lombok.Getter; +import lombok.Setter; import org.apache.commons.lang3.tuple.Pair; import org.gridsuite.modification.server.NetworkModificationException; import org.gridsuite.modification.server.dto.ModificationInfos; @@ -23,10 +24,12 @@ import org.gridsuite.modification.server.dto.NetworkModificationResult.ApplicationStatus; import org.gridsuite.modification.server.dto.ReportInfos; import org.gridsuite.modification.server.elasticsearch.EquipmentInfosService; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.service.FilterService; import org.gridsuite.modification.server.service.ReportService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.List; @@ -50,6 +53,10 @@ public class NetworkModificationApplicator { @Getter private final FilterService filterService; + @Value("${impacts.collection-threshold:50}") + @Setter // TODO REMOVE when VoltageInitReportTest will no longer use NetworkModificationApplicator + private Integer collectionThreshold; + public NetworkModificationApplicator(NetworkStoreService networkStoreService, EquipmentInfosService equipmentInfosService, ReportService reportService, FilterService filterService) { this.networkStoreService = networkStoreService; @@ -59,33 +66,40 @@ public NetworkModificationApplicator(NetworkStoreService networkStoreService, Eq } public NetworkModificationResult applyModifications(List modificationInfosList, NetworkInfos networkInfos, ReportInfos reportInfos) { - NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService); - ApplicationStatus applicationStatus = apply(modificationInfosList, listener.getNetwork(), reportInfos); - listener.setApplicationStatus(applicationStatus); - listener.setLastGroupApplicationStatus(applicationStatus); - return listener.flushNetworkModifications(); + NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService, collectionThreshold); + ApplicationStatus groupApplicationStatus = apply(modificationInfosList, listener.getNetwork(), reportInfos); + List networkImpacts = listener.flushNetworkModifications(); + return + NetworkModificationResult.builder() + .applicationStatus(groupApplicationStatus) + .lastGroupApplicationStatus(groupApplicationStatus) + .networkImpacts(networkImpacts) + .build(); } public NetworkModificationResult applyModifications(List>> modificationInfosGroups, NetworkInfos networkInfos, UUID reportUuid) { - NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService); - List groupsStatuses = + NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService, collectionThreshold); + List groupsApplicationStatuses = modificationInfosGroups.stream() .map(g -> apply(g.getRight(), listener.getNetwork(), new ReportInfos(reportUuid, g.getLeft()))) .toList(); - listener.setApplicationStatus(groupsStatuses.stream().reduce(ApplicationStatus::max).orElse(ApplicationStatus.ALL_OK)); - listener.setLastGroupApplicationStatus(Streams.findLast(groupsStatuses.stream()).orElse(ApplicationStatus.ALL_OK)); - return listener.flushNetworkModifications(); + List networkImpacts = listener.flushNetworkModifications(); + return NetworkModificationResult.builder() + .applicationStatus(groupsApplicationStatuses.stream().reduce(ApplicationStatus::max).orElse(ApplicationStatus.ALL_OK)) + .lastGroupApplicationStatus(Streams.findLast(groupsApplicationStatuses.stream()).orElse(ApplicationStatus.ALL_OK)) + .networkImpacts(networkImpacts) + .build(); } private ApplicationStatus apply(List modificationInfosList, Network network, ReportInfos reportInfos) { String rootReporterId = reportInfos.getReporterId() + "@" + NETWORK_MODIFICATION_TYPE_REPORT; ReporterModel reporter = new ReporterModel(rootReporterId, rootReporterId); - ApplicationStatus applicationStatus = modificationInfosList.stream() + ApplicationStatus groupApplicationStatus = modificationInfosList.stream() .map(m -> apply(m, network, reporter)) .reduce(ApplicationStatus::max) .orElse(ApplicationStatus.ALL_OK); reportService.sendReport(reportInfos.getReportUuid(), reporter); - return applicationStatus; + return groupApplicationStatus; } private ApplicationStatus apply(ModificationInfos modificationInfos, Network network, ReporterModel reporter) { diff --git a/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java b/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java index ffc30e832..95b7b04d1 100644 --- a/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java +++ b/src/main/java/org/gridsuite/modification/server/modifications/NetworkStoreListener.java @@ -9,14 +9,14 @@ import com.google.common.collect.Iterables; import com.powsybl.iidm.network.*; import com.powsybl.network.store.client.NetworkStoreService; -import lombok.Setter; import org.gridsuite.modification.server.NetworkModificationException; -import org.gridsuite.modification.server.dto.NetworkModificationResult; -import org.gridsuite.modification.server.dto.NetworkModificationResult.ApplicationStatus; import org.gridsuite.modification.server.dto.elasticsearch.EquipmentInfos; import org.gridsuite.modification.server.dto.elasticsearch.TombstonedEquipmentInfos; import org.gridsuite.modification.server.elasticsearch.EquipmentInfosService; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; +import org.gridsuite.modification.server.impacts.CollectionElementImpact; import org.gridsuite.modification.server.impacts.SimpleElementImpact; +import org.gridsuite.modification.server.impacts.SimpleElementImpact.SimpleImpactType; import java.util.*; import java.util.stream.Collectors; @@ -43,25 +43,22 @@ public class NetworkStoreListener implements NetworkListener { private final List modifiedEquipments = new ArrayList<>(); - private final Set networkImpacts = new LinkedHashSet<>(); + private final Set simpleImpacts = new LinkedHashSet<>(); - // TODO : Move to the NetworkModificationApplicator class - @Setter - private ApplicationStatus applicationStatus; - @Setter - private ApplicationStatus lastGroupApplicationStatus; + private final Integer collectionThreshold; protected NetworkStoreListener(Network network, UUID networkUuid, - NetworkStoreService networkStoreService, EquipmentInfosService equipmentInfosService) { + NetworkStoreService networkStoreService, EquipmentInfosService equipmentInfosService, Integer collectionThreshold) { this.network = network; this.networkUuid = networkUuid; this.networkStoreService = networkStoreService; this.equipmentInfosService = equipmentInfosService; + this.collectionThreshold = collectionThreshold; } public static NetworkStoreListener create(Network network, UUID networkUuid, NetworkStoreService networkStoreService, - EquipmentInfosService equipmentInfosService) { - var listener = new NetworkStoreListener(network, networkUuid, networkStoreService, equipmentInfosService); + EquipmentInfosService equipmentInfosService, Integer collectionThreshold) { + var listener = new NetworkStoreListener(network, networkUuid, networkStoreService, equipmentInfosService, collectionThreshold); network.addListener(listener); return listener; } @@ -96,13 +93,13 @@ public Network getNetwork() { } private void addSimpleModificationImpact(Identifiable identifiable) { - networkImpacts.add( + simpleImpacts.add( SimpleElementImpact.builder() - .impactType(SimpleElementImpact.SimpleImpactType.MODIFICATION) - .elementType(identifiable.getType()) - .elementId(identifiable.getId()) - .substationIds(getSubstationIds(identifiable)) - .build() + .simpleImpactType(SimpleImpactType.MODIFICATION) + .elementType(identifiable.getType()) + .elementId(identifiable.getId()) + .substationIds(getSubstationIds(identifiable)) + .build() ); } @@ -194,9 +191,9 @@ public void onCreation(Identifiable identifiable) { .voltageLevels(EquipmentInfos.getVoltageLevelsInfos(identifiable)) .substations(EquipmentInfos.getSubstationsInfos(identifiable)) .build()); - networkImpacts.add( + simpleImpacts.add( SimpleElementImpact.builder() - .impactType(SimpleElementImpact.SimpleImpactType.CREATION) + .simpleImpactType(SimpleImpactType.CREATION) .elementType(identifiable.getType()) .elementId(identifiable.getId()) .substationIds(getSubstationIds(identifiable)) @@ -207,9 +204,9 @@ public void onCreation(Identifiable identifiable) { @Override public void beforeRemoval(Identifiable identifiable) { deletedEquipmentsIds.add(identifiable.getId()); - networkImpacts.add( + simpleImpacts.add( SimpleElementImpact.builder() - .impactType(SimpleElementImpact.SimpleImpactType.DELETION) + .simpleImpactType(SimpleImpactType.DELETION) .elementType(identifiable.getType()) .elementId(identifiable.getId()) .substationIds(getSubstationIds(identifiable)) @@ -222,7 +219,7 @@ public void afterRemoval(String identifiableId) { // Do nothing } - public NetworkModificationResult flushNetworkModifications() { + public List flushNetworkModifications() { try { networkStoreService.flush(network); // At first flushEquipmentInfos(); @@ -231,13 +228,7 @@ public NetworkModificationResult flushNetworkModifications() { throw new NetworkModificationException(MODIFICATION_ERROR, e); } - // TODO : Move to the NetworkModificationApplicator class - return - NetworkModificationResult.builder() - .applicationStatus(applicationStatus) - .lastGroupApplicationStatus(lastGroupApplicationStatus) - .networkImpacts(new ArrayList<>(networkImpacts)) - .build(); + return flushNetworkImpacts(); } private static EquipmentInfos toEquipmentInfos(Identifiable identifiable, UUID networkUuid, String variantId) { @@ -275,4 +266,61 @@ private void flushEquipmentInfos() { equipmentInfosService.addAllEquipmentInfos(createdEquipments); equipmentInfosService.addAllEquipmentInfos(modifiedEquipments); } + + private List flushNetworkImpacts() { + if (isAllNetworkImpacted()) { + return List.of(CollectionElementImpact.builder() + .elementType(IdentifiableType.SUBSTATION) + .build()); + } + + return reduceNetworkImpacts(); + } + + private boolean isAllNetworkImpacted() { + Set allImpactedSubstationsIds = simpleImpacts.stream().flatMap(i -> i.getSubstationIds().stream()).collect(Collectors.toSet()); + return allImpactedSubstationsIds.size() >= collectionThreshold; + } + + private List reduceNetworkImpacts() { + List reducedImpacts = new ArrayList<>(); + Set impactedSubstationsIds = new HashSet<>(); + + // Impacts type collection + for (IdentifiableType elementType : IdentifiableType.values()) { + List impacts = getSimpleImpacts(elementType); + if (impacts.size() >= collectionThreshold) { + reducedImpacts.add(CollectionElementImpact.builder() + .elementType(elementType) + .build()); + } else { + impactedSubstationsIds.addAll(impacts.stream().flatMap(i -> i.getSubstationIds().stream()).toList()); + } + } + + // Impacts type simple for substation only + reducedImpacts.addAll( + impactedSubstationsIds.stream().map(id -> + SimpleElementImpact.builder() + .simpleImpactType(SimpleImpactType.MODIFICATION) + .elementType(IdentifiableType.SUBSTATION) + .elementId(id) + .substationIds(Set.of(id)) + .build() + ).toList() + ); + + // Impacts type simple for deletion only + reducedImpacts.addAll(simpleImpacts.stream().filter(SimpleElementImpact::isDeletion).distinct().toList()); + + return reducedImpacts; + } + + private List getSimpleImpacts(IdentifiableType elementType) { + return simpleImpacts.stream() + .filter(i -> !i.isDeletion() && i.getElementType() == elementType) + .distinct() + .toList(); + } + } diff --git a/src/test/java/org/gridsuite/modification/server/Impacts/ElementImpactTest.java b/src/test/java/org/gridsuite/modification/server/Impacts/ElementImpactTest.java index ca6306bc0..553a53a74 100644 --- a/src/test/java/org/gridsuite/modification/server/Impacts/ElementImpactTest.java +++ b/src/test/java/org/gridsuite/modification/server/Impacts/ElementImpactTest.java @@ -6,23 +6,31 @@ */ package org.gridsuite.modification.server.Impacts; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.powsybl.iidm.network.IdentifiableType; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createCollectionElementImpact; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createCreationImpactType; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createDeletionImpactType; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createModificationImpactType; +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + import org.gridsuite.modification.server.dto.NetworkModificationResult; import org.gridsuite.modification.server.dto.NetworkModificationResult.ApplicationStatus; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; +import org.gridsuite.modification.server.impacts.CollectionElementImpact; import org.gridsuite.modification.server.impacts.SimpleElementImpact; import org.gridsuite.modification.server.utils.TestUtils; import org.junit.Test; import org.junit.jupiter.api.Tag; -import java.io.IOException; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.TreeSet; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.powsybl.iidm.network.IdentifiableType; -import static org.gridsuite.modification.server.Impacts.TestImpactUtils.*; -import static org.junit.Assert.assertEquals; +import lombok.SneakyThrows; /** * @author Slimane Amar @@ -37,16 +45,21 @@ public void testElementImpact() throws IOException { SimpleElementImpact modificationImpact = createModificationImpactType(IdentifiableType.LOAD, "loadId", new TreeSet<>(List.of("s3"))); SimpleElementImpact deletionImpact = createDeletionImpactType(IdentifiableType.GENERATOR, "generatorId", new TreeSet<>(List.of("s4"))); - Collection impacts = List.of(creationImpact, modificationImpact, deletionImpact); + assertTrue(creationImpact.isSimple()); + assertTrue(creationImpact.isCreation()); + assertTrue(modificationImpact.isModification()); + assertTrue(deletionImpact.isDeletion()); + + List impacts = List.of(creationImpact, modificationImpact, deletionImpact); - assertEquals("{\"impactType\":\"CREATION\",\"elementId\":\"lineId\",\"elementType\":\"LINE\",\"substationIds\":[\"s1\",\"s2\"]}", mapper.writeValueAsString(creationImpact)); - assertEquals("{\"impactType\":\"MODIFICATION\",\"elementId\":\"loadId\",\"elementType\":\"LOAD\",\"substationIds\":[\"s3\"]}", mapper.writeValueAsString(modificationImpact)); - assertEquals("{\"impactType\":\"DELETION\",\"elementId\":\"generatorId\",\"elementType\":\"GENERATOR\",\"substationIds\":[\"s4\"]}", mapper.writeValueAsString(deletionImpact)); + assertEquals("{\"type\":\"SIMPLE\",\"elementType\":\"LINE\",\"simpleImpactType\":\"CREATION\",\"elementId\":\"lineId\",\"substationIds\":[\"s1\",\"s2\"]}", mapper.writeValueAsString(creationImpact)); + assertEquals("{\"type\":\"SIMPLE\",\"elementType\":\"LOAD\",\"simpleImpactType\":\"MODIFICATION\",\"elementId\":\"loadId\",\"substationIds\":[\"s3\"]}", mapper.writeValueAsString(modificationImpact)); + assertEquals("{\"type\":\"SIMPLE\",\"elementType\":\"GENERATOR\",\"simpleImpactType\":\"DELETION\",\"elementId\":\"generatorId\",\"substationIds\":[\"s4\"]}", mapper.writeValueAsString(deletionImpact)); NetworkModificationResult result = NetworkModificationResult.builder() .applicationStatus(ApplicationStatus.ALL_OK) .lastGroupApplicationStatus(ApplicationStatus.ALL_OK) - .networkImpacts((List) impacts) + .networkImpacts(impacts) .build(); assertEquals(TestUtils.resourceToString("/network-modification-result-with-all-ok.json"), mapper.writeValueAsString(result)); @@ -60,8 +73,38 @@ public void testElementImpact() throws IOException { assertEquals("[s1, s2, s3, s4]", result.getImpactedSubstationsIds().toString()); - impacts = new HashSet<>(List.of(creationImpact, creationImpact, creationImpact)); + Set impactsSet = Set.copyOf(List.of(creationImpact, creationImpact, creationImpact)); + + assertEquals("[{\"type\":\"SIMPLE\",\"elementType\":\"LINE\",\"simpleImpactType\":\"CREATION\",\"elementId\":\"lineId\",\"substationIds\":[\"s1\",\"s2\"]}]", mapper.writeValueAsString(impactsSet)); + } + + @Test + @SneakyThrows + public void testCollectionElementImpact() { + + CollectionElementImpact linesCollectionImpact = createCollectionElementImpact(IdentifiableType.LINE); + CollectionElementImpact loadsCollectionImpact = createCollectionElementImpact(IdentifiableType.LOAD); + CollectionElementImpact generatorsCollectionImpact = createCollectionElementImpact(IdentifiableType.GENERATOR); + + assertTrue(linesCollectionImpact.isCollection()); + + assertEquals("{\"type\":\"COLLECTION\",\"elementType\":\"LINE\"}", mapper.writeValueAsString(linesCollectionImpact)); + assertEquals("{\"type\":\"COLLECTION\",\"elementType\":\"LOAD\"}", mapper.writeValueAsString(loadsCollectionImpact)); + assertEquals("{\"type\":\"COLLECTION\",\"elementType\":\"GENERATOR\"}", mapper.writeValueAsString(generatorsCollectionImpact)); + + List impacts = List.of(linesCollectionImpact, loadsCollectionImpact, generatorsCollectionImpact); + + NetworkModificationResult result = NetworkModificationResult.builder() + .applicationStatus(ApplicationStatus.ALL_OK) + .lastGroupApplicationStatus(ApplicationStatus.ALL_OK) + .networkImpacts(impacts) + .build(); + assertEquals(TestUtils.resourceToString("/network-modification-result-collection-impacts-with-all-ok.json"), mapper.writeValueAsString(result)); + + assertEquals(Set.of(), result.getImpactedSubstationsIds()); + + Set impactsSet = Set.copyOf(List.of(linesCollectionImpact, linesCollectionImpact, linesCollectionImpact)); - assertEquals("[{\"impactType\":\"CREATION\",\"elementId\":\"lineId\",\"elementType\":\"LINE\",\"substationIds\":[\"s1\",\"s2\"]}]", mapper.writeValueAsString(impacts)); + assertEquals("[{\"type\":\"COLLECTION\",\"elementType\":\"LINE\"}]", mapper.writeValueAsString(impactsSet)); } } diff --git a/src/test/java/org/gridsuite/modification/server/Impacts/TestImpactUtils.java b/src/test/java/org/gridsuite/modification/server/Impacts/TestImpactUtils.java index 123c4e918..25a14d3b7 100644 --- a/src/test/java/org/gridsuite/modification/server/Impacts/TestImpactUtils.java +++ b/src/test/java/org/gridsuite/modification/server/Impacts/TestImpactUtils.java @@ -13,10 +13,13 @@ import org.apache.commons.lang3.tuple.Pair; import org.gridsuite.modification.server.dto.NetworkModificationResult; import org.gridsuite.modification.server.dto.NetworkModificationResult.ApplicationStatus; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; +import org.gridsuite.modification.server.impacts.CollectionElementImpact; import org.gridsuite.modification.server.impacts.SimpleElementImpact; import org.gridsuite.modification.server.impacts.SimpleElementImpact.SimpleImpactType; import java.util.*; +import java.util.stream.Collectors; import static org.gridsuite.modification.server.utils.assertions.Assertions.*; import static org.junit.Assert.assertEquals; @@ -56,16 +59,17 @@ private static void testEmptyImpacts(ApplicationStatus globalApplicationStatusEx assertThat(networkModificationResult).recursivelyEquals(resultExpected); } - public static void testElementImpacts(ObjectMapper mapper, String resultAsString, int nbImpacts, Set substationIds) throws JsonProcessingException { + public static void testElementImpacts(ObjectMapper mapper, String resultAsString, int nbImpacts, Set elementTypes, Set substationIds) throws JsonProcessingException { Optional networkModificationResult = mapper.readValue(resultAsString, new TypeReference<>() { }); assertTrue(networkModificationResult.isPresent()); assertEquals(ApplicationStatus.ALL_OK, networkModificationResult.get().getApplicationStatus()); assertEquals(new TreeSet<>(substationIds), networkModificationResult.get().getImpactedSubstationsIds()); assertEquals(nbImpacts, networkModificationResult.get().getNetworkImpacts().size()); + assertThat(networkModificationResult.get().getNetworkImpacts()).containsAll(elementTypes.stream().map(TestImpactUtils::createCollectionElementImpact).toList()); } - public static void testElementImpacts(ObjectMapper mapper, String resultAsString, List elementImpactsExpected) throws JsonProcessingException { + public static void testElementImpacts(ObjectMapper mapper, String resultAsString, List elementImpactsExpected) throws JsonProcessingException { Optional networkModificationResult = mapper.readValue(resultAsString, new TypeReference<>() { }); assertTrue(networkModificationResult.isPresent()); NetworkModificationResult resultExpected = NetworkModificationResult.builder() @@ -84,13 +88,13 @@ public static void testElementModificationImpact(ObjectMapper mapper, String res testElementImpact(SimpleImpactType.MODIFICATION, mapper, resultAsString, elementType, elementId, substationIds); } - public static void testElementImpact(SimpleImpactType impactType, ObjectMapper mapper, String resultAsString, IdentifiableType elementType, String elementId, Set substationIds) throws JsonProcessingException { + public static void testElementImpact(SimpleImpactType type, ObjectMapper mapper, String resultAsString, IdentifiableType elementType, String elementId, Set substationIds) throws JsonProcessingException { Optional networkModificationResult = mapper.readValue(resultAsString, new TypeReference<>() { }); assertTrue(networkModificationResult.isPresent()); NetworkModificationResult resultExpected = NetworkModificationResult.builder() .applicationStatus(ApplicationStatus.ALL_OK) .lastGroupApplicationStatus(ApplicationStatus.ALL_OK) - .networkImpacts(List.of(createElementImpact(impactType, elementType, elementId, new HashSet<>(substationIds)))) + .networkImpacts(createSubstationImpacts(substationIds)) .build(); assertThat(networkModificationResult.get()).recursivelyEquals(resultExpected); } @@ -108,7 +112,7 @@ public static void testConnectableDeletionImpacts(ObjectMapper mapper, String re assertThat(networkModificationResult.get()).recursivelyEquals(resultExpected); } - private static List createConnectableDeletionImpacts(IdentifiableType connectableType, String connectableId, + private static List createConnectableDeletionImpacts(IdentifiableType connectableType, String connectableId, String breakerId, String disconnectorId, String substationId) { return List.of( createDeletionImpactType(IdentifiableType.SWITCH, breakerId, Set.of(substationId)), @@ -125,11 +129,8 @@ public static void testBranchCreationImpacts(ObjectMapper mapper, String resultA } public static void testBranchCreationImpacts(ObjectMapper mapper, String resultAsString, IdentifiableType elementType, String elementId, Set substationIds) throws JsonProcessingException { - List impacts = List.of( - createElementImpact(SimpleImpactType.CREATION, elementType, elementId, new TreeSet<>(substationIds)), - createElementImpact(SimpleImpactType.MODIFICATION, elementType, elementId, new TreeSet<>(substationIds)) // case with newCurrentLimits1/newtapChanger - ); - testElementImpacts(mapper, resultAsString, impacts); + List substationsImpacts = createSubstationImpacts(substationIds); + testElementImpacts(mapper, resultAsString, substationsImpacts); } public static void testBranchDeletionImpacts(ObjectMapper mapper, String resultAsString, @@ -139,7 +140,7 @@ public static void testBranchDeletionImpacts(ObjectMapper mapper, String resultA testBranchImpacts(mapper, SimpleImpactType.DELETION, resultAsString, branchType, branchId, breakerId1, disconnectorId1, substationId1, breakerId2, disconnectorId2, substationId2); } - public static void testBranchImpacts(ObjectMapper mapper, SimpleImpactType impactType, String resultAsString, + public static void testBranchImpacts(ObjectMapper mapper, SimpleImpactType type, String resultAsString, IdentifiableType branchType, String branchId, String breakerId1, String disconnectorId1, String substationId1, String breakerId2, String disconnectorId2, String substationId2) throws JsonProcessingException { @@ -148,31 +149,24 @@ public static void testBranchImpacts(ObjectMapper mapper, SimpleImpactType impac NetworkModificationResult resultExpected = NetworkModificationResult.builder() .applicationStatus(ApplicationStatus.ALL_OK) .lastGroupApplicationStatus(ApplicationStatus.ALL_OK) - .networkImpacts(createBranchImpacts(impactType, branchType, branchId, breakerId1, disconnectorId1, substationId1, breakerId2, disconnectorId2, substationId2)) + .networkImpacts(createBranchImpacts(type, branchType, branchId, breakerId1, disconnectorId1, substationId1, breakerId2, disconnectorId2, substationId2)) .build(); assertThat(networkModificationResult.get()).recursivelyEquals(resultExpected); } - private static List createBranchImpacts(SimpleImpactType impactType, IdentifiableType branchType, String branchId, + private static List createBranchImpacts(SimpleImpactType type, IdentifiableType branchType, String branchId, String breakerId1, String disconnectorId1, String substationId1, String breakerId2, String disconnectorId2, String substationId2) { - LinkedList impacts = new LinkedList<>(List.of(createElementImpact(impactType, branchType, branchId, new HashSet<>(List.of(substationId1, substationId2))))); - List switchImpacts = List.of( - createElementImpact(impactType, IdentifiableType.SWITCH, breakerId1, Set.of(substationId1)), - createElementImpact(impactType, IdentifiableType.SWITCH, disconnectorId1, Set.of(substationId1)), - createElementImpact(impactType, IdentifiableType.SWITCH, breakerId2, Set.of(substationId2)), - createElementImpact(impactType, IdentifiableType.SWITCH, disconnectorId2, Set.of(substationId2)) - ); - if (impactType == SimpleImpactType.CREATION) { - impacts.add(createElementImpact(SimpleImpactType.MODIFICATION, branchType, branchId, new TreeSet<>(List.of(substationId1, substationId2)))); // case with newtapChanger - } - if (impactType == SimpleImpactType.DELETION) { - impacts.addAll(0, switchImpacts); - } else { - impacts.addAll(switchImpacts); + if (type == SimpleImpactType.DELETION) { + return List.of( + createElementImpact(SimpleImpactType.DELETION, branchType, branchId, Set.copyOf(List.of(substationId1, substationId2))), + createElementImpact(SimpleImpactType.DELETION, IdentifiableType.SWITCH, breakerId1, Set.of(substationId1)), + createElementImpact(SimpleImpactType.DELETION, IdentifiableType.SWITCH, disconnectorId1, Set.of(substationId1)), + createElementImpact(SimpleImpactType.DELETION, IdentifiableType.SWITCH, breakerId2, Set.of(substationId2)), + createElementImpact(SimpleImpactType.DELETION, IdentifiableType.SWITCH, disconnectorId2, Set.of(substationId2)) + ); } - - return impacts; + return createSubstationImpacts(Set.copyOf(List.of(substationId1, substationId2))); } public static void test3WTDeletionImpacts(ObjectMapper mapper, String resultAsString, String w3tId, @@ -190,7 +184,7 @@ public static void test3WTDeletionImpacts(ObjectMapper mapper, String resultAsSt assertThat(networkModificationResult.get()).recursivelyEquals(resultExpected); } - private static List create3wtDeletionImpacts(String w3tId, + private static List create3wtDeletionImpacts(String w3tId, String breakerId1, String disconnectorId1, String breakerId2, String disconnectorId2, String breakerId3, String disconnectorId3, @@ -206,10 +200,15 @@ private static List create3wtDeletionImpacts(String w3tId, ); } - public static List createMultipleDeletionImpacts(List> deletedIdentifiables, Set impactedSubstationIds) { + public static List createMultipleDeletionImpacts(List> deletedIdentifiables, Set impactedSubstationIds) { return new ArrayList<>(deletedIdentifiables.stream().map(identifiable -> createDeletionImpactType(identifiable.getLeft(), identifiable.getRight(), impactedSubstationIds)).toList()); } + public static List createSubstationImpacts(Set substationIds) { + return substationIds.stream().map(id -> createElementImpact(SimpleImpactType.MODIFICATION, IdentifiableType.SUBSTATION, id, Set.of(id))) + .collect(Collectors.toList()); + } + public static SimpleElementImpact createCreationImpactType(IdentifiableType elementType, String elementId, Set substationIds) { return createElementImpact(SimpleImpactType.CREATION, elementType, elementId, substationIds); } @@ -222,11 +221,17 @@ public static SimpleElementImpact createModificationImpactType(IdentifiableType return createElementImpact(SimpleImpactType.MODIFICATION, elementType, elementId, substationIds); } - private static SimpleElementImpact createElementImpact(SimpleImpactType impactType, IdentifiableType elementType, String elementId, Set substationIds) { + private static SimpleElementImpact createElementImpact(SimpleImpactType type, IdentifiableType elementType, String elementId, Set substationIds) { return SimpleElementImpact.builder() - .impactType(impactType) + .simpleImpactType(type) .elementType(elementType) .elementId(elementId) .substationIds(substationIds).build(); } + + public static CollectionElementImpact createCollectionElementImpact(IdentifiableType elementType) { + return CollectionElementImpact.builder() + .elementType(elementType) + .build(); + } } diff --git a/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java b/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java index 95d4dcd34..344bc5c48 100644 --- a/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java +++ b/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java @@ -28,6 +28,7 @@ import org.gridsuite.modification.server.elasticsearch.EquipmentInfosRepository; import org.gridsuite.modification.server.elasticsearch.EquipmentInfosService; import org.gridsuite.modification.server.elasticsearch.TombstonedEquipmentInfosRepository; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.impacts.SimpleElementImpact; import org.gridsuite.modification.server.modifications.ModificationUtils; import org.gridsuite.modification.server.repositories.NetworkModificationRepository; @@ -980,7 +981,7 @@ public void testTombstonedEquipmentInfos() throws Exception { mvcResult = mockMvc.perform(post(URI_NETWORK_MODIF).content(equipmentDeletionInfosJson).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()).andReturn(); assertApplicationStatusOK(mvcResult); - List expectedImpacts = createMultipleDeletionImpacts( + List expectedImpacts = createMultipleDeletionImpacts( List.of( Pair.of(IdentifiableType.HVDC_LINE, "hvdcLine"), Pair.of(IdentifiableType.HVDC_CONVERTER_STATION, "v1lcc"), Pair.of(IdentifiableType.HVDC_CONVERTER_STATION, "v2vsc"), @@ -1125,12 +1126,16 @@ private void test3WTDeletionImpacts(String resultAsString, String w3tId, assertTrue(existTombstonedEquipmentInfos(disconnectorId3, TEST_NETWORK_ID, VariantManagerConstants.INITIAL_VARIANT_ID)); } - private void testMultipleDeletionImpacts(String networkModificationResultAsString, List expectedImpacts) throws JsonProcessingException { - // All equipments have been removed from network - expectedImpacts.forEach(impact -> assertNull(network.getIdentifiable(impact.getElementId()))); + private void testMultipleDeletionImpacts(String networkModificationResultAsString, List expectedImpacts) throws JsonProcessingException { + for (AbstractBaseImpact impact : expectedImpacts) { + if (impact instanceof SimpleElementImpact simpleImpact) { + // Equipment has been removed from network + assertNull(network.getIdentifiable(simpleImpact.getElementId())); - // All equipments have been added as TombstonedEquipmentInfos in ElasticSearch - expectedImpacts.forEach(impact -> assertTrue(existTombstonedEquipmentInfos(impact.getElementId(), TEST_NETWORK_ID, VariantManagerConstants.INITIAL_VARIANT_ID))); + // Equipment has been added as TombstonedEquipmentInfos in ElasticSearch + assertTrue(existTombstonedEquipmentInfos(simpleImpact.getElementId(), TEST_NETWORK_ID, VariantManagerConstants.INITIAL_VARIANT_ID)); + } + } TestImpactUtils.testElementImpacts(mapper, networkModificationResultAsString, expectedImpacts); } diff --git a/src/test/java/org/gridsuite/modification/server/VoltageInitReportTest.java b/src/test/java/org/gridsuite/modification/server/VoltageInitReportTest.java index d002f6ef3..6f43a74fd 100644 --- a/src/test/java/org/gridsuite/modification/server/VoltageInitReportTest.java +++ b/src/test/java/org/gridsuite/modification/server/VoltageInitReportTest.java @@ -65,6 +65,7 @@ void testVoltageInitDuplicationLogs(final ApplicationStatus resultStatus, final (restClient_, preloadingStrategy, executorService) -> new CachedNetworkStoreClient(new OfflineNetworkStoreClient())); final EquipmentInfosService equipmentInfosService = Mockito.mock(EquipmentInfosService.class); final NetworkModificationApplicator networkModificationApplicator = new NetworkModificationApplicator(networkStoreService, equipmentInfosService, reportService, null); + networkModificationApplicator.setCollectionThreshold(5); final Network network = Network.read(Paths.get(this.getClass().getClassLoader().getResource("fourSubstations_testsOpenReac.xiidm").toURI())); diff --git a/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java index 801061080..9297f1fdb 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/AbstractByFormulaModificationTest.java @@ -20,6 +20,7 @@ import org.gridsuite.modification.server.dto.formula.FormulaInfos; import org.gridsuite.modification.server.dto.formula.Operator; import org.gridsuite.modification.server.dto.formula.ReferenceFieldOrValue; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.service.FilterService; import org.gridsuite.modification.server.utils.NetworkCreation; import org.junit.Before; @@ -34,6 +35,8 @@ import java.util.UUID; import java.util.stream.Collectors; +import static org.assertj.core.api.Assertions.assertThat; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createCollectionElementImpact; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -62,6 +65,11 @@ public abstract class AbstractByFormulaModificationTest extends AbstractNetworkM public static final String PATH = "/v1/filters/export"; + @Override + protected void assertResultImpacts(List impacts) { + assertThat(impacts).containsExactly(createCollectionElementImpact(getIdentifiableType())); + } + @Before public void specificSetUp() { FilterService.setFilterServerBaseUri(wireMockServer.baseUrl()); diff --git a/src/test/java/org/gridsuite/modification/server/modifications/AbstractNetworkModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/AbstractNetworkModificationTest.java index 0e0fee91d..10b87cf23 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/AbstractNetworkModificationTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/AbstractNetworkModificationTest.java @@ -18,6 +18,7 @@ import com.powsybl.network.store.iidm.impl.NetworkImpl; import org.gridsuite.modification.server.dto.ModificationInfos; import org.gridsuite.modification.server.dto.NetworkModificationResult; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.entities.ModificationEntity; import org.gridsuite.modification.server.repositories.NetworkModificationRepository; import org.gridsuite.modification.server.service.ReportService; @@ -48,6 +49,7 @@ import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static org.gridsuite.modification.server.utils.assertions.Assertions.*; +import static org.gridsuite.modification.server.utils.assertions.Assertions.assertThat; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -127,6 +129,9 @@ public void tearOff() { } } + protected void assertResultImpacts(List impacts) { + } + @Test public void testCreate() throws Exception { MvcResult mvcResult; @@ -138,6 +143,7 @@ public void testCreate() throws Exception { .andExpect(status().isOk()).andReturn(); networkModificationResult = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); assertTrue(networkModificationResult.isPresent()); + assertResultImpacts(networkModificationResult.get().getNetworkImpacts()); assertNotEquals(NetworkModificationResult.ApplicationStatus.WITH_ERRORS, networkModificationResult.get().getApplicationStatus()); ModificationInfos createdModification = modificationRepository.getModifications(TEST_GROUP_ID, false, true).get(0); diff --git a/src/test/java/org/gridsuite/modification/server/modifications/GeneratorScalingTest.java b/src/test/java/org/gridsuite/modification/server/modifications/GeneratorScalingTest.java index 7296b2f6c..db1686ac6 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/GeneratorScalingTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/GeneratorScalingTest.java @@ -15,6 +15,7 @@ import org.gridsuite.modification.server.VariationMode; import org.gridsuite.modification.server.VariationType; import org.gridsuite.modification.server.dto.*; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.service.FilterService; import org.gridsuite.modification.server.utils.NetworkCreation; import org.junit.Before; @@ -29,7 +30,9 @@ import java.util.UUID; import java.util.stream.Collectors; +import static org.assertj.core.api.Assertions.assertThat; import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createCollectionElementImpact; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -105,6 +108,11 @@ private List getTestFilters() { return List.of(filter1, filter2, filter3, filter4, filter5); } + @Override + protected void assertResultImpacts(List impacts) { + assertThat(impacts).containsExactly(createCollectionElementImpact(IdentifiableType.GENERATOR)); + } + @Test @Override public void testCreate() throws Exception { diff --git a/src/test/java/org/gridsuite/modification/server/modifications/LoadByFormulaModificationTest.java b/src/test/java/org/gridsuite/modification/server/modifications/LoadByFormulaModificationTest.java index 1ee9a4170..c31efa579 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/LoadByFormulaModificationTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/LoadByFormulaModificationTest.java @@ -14,6 +14,7 @@ import org.gridsuite.modification.server.dto.formula.Operator; import org.gridsuite.modification.server.dto.formula.ReferenceFieldOrValue; import org.gridsuite.modification.server.dto.formula.equipmentfield.LoadField; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import java.util.List; @@ -101,4 +102,9 @@ protected void assertAfterNetworkModificationDeletion() { assertEquals(70, getNetwork().getLoad(LOAD_ID_3).getQ0(), 0); assertEquals(150, getNetwork().getLoad(LOAD_ID_4).getQ0(), 0); } + + @Override + protected void assertResultImpacts(List impacts) { + // TODO later + } } diff --git a/src/test/java/org/gridsuite/modification/server/modifications/LoadScalingTest.java b/src/test/java/org/gridsuite/modification/server/modifications/LoadScalingTest.java index fa4a4d2c5..611ec261d 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/LoadScalingTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/LoadScalingTest.java @@ -16,6 +16,7 @@ import org.gridsuite.modification.server.VariationMode; import org.gridsuite.modification.server.VariationType; import org.gridsuite.modification.server.dto.*; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.service.FilterService; import org.gridsuite.modification.server.utils.NetworkCreation; import org.hamcrest.core.IsNull; @@ -31,7 +32,9 @@ import java.util.UUID; import java.util.stream.Collectors; +import static org.assertj.core.api.Assertions.assertThat; import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createCollectionElementImpact; import static org.junit.Assert.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -127,6 +130,11 @@ private List getTestFilters() { return List.of(filter1, filter2, filter3, filter4, filter5); } + @Override + protected void assertResultImpacts(List impacts) { + assertThat(impacts).containsExactly(createCollectionElementImpact(IdentifiableType.LOAD)); + } + @Test @Override public void testCreate() throws Exception { diff --git a/src/test/java/org/gridsuite/modification/server/modifications/tabularcreations/TabularGeneratorCreationsTest.java b/src/test/java/org/gridsuite/modification/server/modifications/tabularcreations/TabularGeneratorCreationsTest.java index ebf4f5e70..732caa626 100644 --- a/src/test/java/org/gridsuite/modification/server/modifications/tabularcreations/TabularGeneratorCreationsTest.java +++ b/src/test/java/org/gridsuite/modification/server/modifications/tabularcreations/TabularGeneratorCreationsTest.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.powsybl.iidm.network.EnergySource; +import com.powsybl.iidm.network.IdentifiableType; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.extensions.ConnectablePosition; import lombok.SneakyThrows; @@ -16,6 +17,7 @@ import org.gridsuite.modification.server.dto.GeneratorCreationInfos; import org.gridsuite.modification.server.dto.ModificationInfos; import org.gridsuite.modification.server.dto.TabularCreationInfos; +import org.gridsuite.modification.server.impacts.AbstractBaseImpact; import org.gridsuite.modification.server.modifications.AbstractNetworkModificationTest; import org.gridsuite.modification.server.utils.NetworkCreation; import org.junit.Test; @@ -29,7 +31,9 @@ import static com.vladmihalcea.sql.SQLStatementCountValidator.assertSelectCount; import static com.vladmihalcea.sql.SQLStatementCountValidator.reset; +import static org.assertj.core.api.Assertions.assertThat; import static org.gridsuite.modification.server.utils.TestUtils.assertLogMessage; +import static org.gridsuite.modification.server.Impacts.TestImpactUtils.createCollectionElementImpact; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -90,6 +94,13 @@ protected ModificationInfos buildModification() { .regulatingTerminalId("v5load").regulatingTerminalType("LOAD").regulatingTerminalVlId("v5").qPercent(75D) .reactiveCapabilityCurve(false).reactiveCapabilityCurvePoints(List.of()) .build(), + GeneratorCreationInfos.builder() + .equipmentId("id5").voltageLevelId("v5").busOrBusbarSectionId("1A1") + .connectionName("name5").connectionDirection(ConnectablePosition.Direction.BOTTOM).connectionPosition(100).connected(false).connected(true) + .energySource(EnergySource.WIND).minActivePower(0).maxActivePower(200) + .activePowerSetpoint(150).voltageRegulationOn(true).voltageSetpoint(375D) + .reactiveCapabilityCurve(false).reactiveCapabilityCurvePoints(List.of()) + .build(), GeneratorCreationInfos.builder() .equipmentId("v5generator").voltageLevelId("v5").busOrBusbarSectionId("1A1") .connectionName("v5generator").connectionDirection(ConnectablePosition.Direction.BOTTOM).connectionPosition(100).connected(false).connected(true) @@ -144,7 +155,8 @@ protected void assertAfterNetworkModificationCreation() { assertNotNull(getNetwork().getGenerator("id2")); assertNotNull(getNetwork().getGenerator("id3")); assertNotNull(getNetwork().getGenerator("id4")); - assertLogMessage("Tabular creation: 4 generators have been created and 1 have not been created", "tabularGENERATOR_CREATIONWarning", reportService); + assertNotNull(getNetwork().getGenerator("id5")); + assertLogMessage("Tabular creation: 5 generators have been created and 1 have not been created", "tabularGENERATOR_CREATIONWarning", reportService); assertLogMessage("GENERATOR_ALREADY_EXISTS : v5generator", ModificationType.GENERATOR_CREATION.name() + "1", reportService); } @@ -154,6 +166,12 @@ protected void assertAfterNetworkModificationDeletion() { assertNull(getNetwork().getGenerator("id2")); assertNull(getNetwork().getGenerator("id3")); assertNull(getNetwork().getGenerator("id4")); + assertNull(getNetwork().getGenerator("id5")); + } + + @Override + protected void assertResultImpacts(List impacts) { + assertThat(impacts).containsExactly(createCollectionElementImpact(IdentifiableType.SWITCH), createCollectionElementImpact(IdentifiableType.GENERATOR)); } @Test @@ -165,7 +183,7 @@ public void testCheckSqlRequestsCount() throws Exception { status().isOk(), content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); // We check that the request count is not dependent on the number of sub creations of the tabular creation (the JPA N+1 problem is correctly solved) - assertSelectCount(8); + assertSelectCount(9); List creations = List.of( GeneratorCreationInfos.builder() @@ -198,7 +216,7 @@ public void testCheckSqlRequestsCount() throws Exception { mockMvc.perform(get("/v1/groups/{groupUuid}/network-modifications", getGroupId())) .andExpect(status().isOk()); // We check that the request count is not dependent on the number of sub creations of the tabular creation (the JPA N+1 problem is correctly solved) - assertSelectCount(12); + assertSelectCount(13); } @Test 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 cdbc637a0..f9f504d28 100644 --- a/src/test/java/org/gridsuite/modification/server/service/BuildTest.java +++ b/src/test/java/org/gridsuite/modification/server/service/BuildTest.java @@ -718,7 +718,12 @@ public void runBuildTest() throws Exception { Message resultMessage = output.receive(TIMEOUT, buildResultDestination); assertNotNull(resultMessage); assertEquals("me", resultMessage.getHeaders().get("receiver")); - testElementImpacts(mapper, new String(resultMessage.getPayload()), 61, Set.of("newSubstation", "s1", "s2")); + // 2 : LOAD and SWITCH equipments are reduced to collection impact + // + 2 substation modifications + // (newSubstation is created but transformed to modification type (see NetworkStoreListener::reduceNetworkImpacts)) + // + 3 Equipment deletions ( 1 shunt compensator + 2 switch) + // = 7 + testElementImpacts(mapper, new String(resultMessage.getPayload()), 7, Set.of(IdentifiableType.LOAD, IdentifiableType.SWITCH), Set.of("newSubstation", "s1")); Message buildMessage = output.receive(TIMEOUT, consumeBuildDestination); assertNotNull(buildMessage); assertEquals("me", buildMessage.getHeaders().get("receiver")); @@ -863,7 +868,10 @@ public void runBuildTest() throws Exception { resultMessage = output.receive(TIMEOUT, buildResultDestination); assertNotNull(resultMessage); assertEquals("me", resultMessage.getHeaders().get("receiver")); - testElementImpacts(mapper, new String(resultMessage.getPayload()), 55, Set.of("newSubstation", "s1", "s2")); + // 1 : SWITCH equipments are reduced to collection impact + // + 2 substation modifications + // = 3 + testElementImpacts(mapper, new String(resultMessage.getPayload()), 3, Set.of(IdentifiableType.SWITCH), Set.of("newSubstation", "s1")); buildMessage = output.receive(TIMEOUT, consumeBuildDestination); assertNotNull(buildMessage); assertEquals("me", buildMessage.getHeaders().get("receiver")); diff --git a/src/test/resources/application-default.yml b/src/test/resources/application-default.yml index b35c31bd5..0ddd926e3 100644 --- a/src/test/resources/application-default.yml +++ b/src/test/resources/application-default.yml @@ -29,5 +29,8 @@ powsybl-ws: query: ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE hostPort: ":" +impacts: + collection-threshold: 5 + diff --git a/src/test/resources/network-modification-result-collection-impacts-with-all-ok.json b/src/test/resources/network-modification-result-collection-impacts-with-all-ok.json new file mode 100644 index 000000000..979bd5862 --- /dev/null +++ b/src/test/resources/network-modification-result-collection-impacts-with-all-ok.json @@ -0,0 +1,19 @@ +{ + "applicationStatus": "ALL_OK", + "lastGroupApplicationStatus": "ALL_OK", + "networkImpacts": [ + { + "type": "COLLECTION", + "elementType": "LINE" + }, + { + "type": "COLLECTION", + "elementType": "LOAD" + }, + { + "type": "COLLECTION", + "elementType": "GENERATOR" + } + ], + "impactedSubstationsIds": [] + } diff --git a/src/test/resources/network-modification-result-with-all-ok.json b/src/test/resources/network-modification-result-with-all-ok.json index fbee3929a..23fb2fb03 100644 --- a/src/test/resources/network-modification-result-with-all-ok.json +++ b/src/test/resources/network-modification-result-with-all-ok.json @@ -3,26 +3,29 @@ "lastGroupApplicationStatus": "ALL_OK", "networkImpacts": [ { - "impactType": "CREATION", - "elementId": "lineId", + "type": "SIMPLE", "elementType": "LINE", + "simpleImpactType": "CREATION", + "elementId": "lineId", "substationIds": [ "s1", "s2" ] }, { - "impactType": "MODIFICATION", - "elementId": "loadId", + "type": "SIMPLE", "elementType": "LOAD", + "simpleImpactType": "MODIFICATION", + "elementId": "loadId", "substationIds": [ "s3" ] }, { - "impactType": "DELETION", - "elementId": "generatorId", + "type": "SIMPLE", "elementType": "GENERATOR", + "simpleImpactType": "DELETION", + "elementId": "generatorId", "substationIds": [ "s4" ] diff --git a/src/test/resources/network-modification-result-with-with-errors.json b/src/test/resources/network-modification-result-with-with-errors.json index b40bd6902..c1fe15a9e 100644 --- a/src/test/resources/network-modification-result-with-with-errors.json +++ b/src/test/resources/network-modification-result-with-with-errors.json @@ -3,26 +3,29 @@ "lastGroupApplicationStatus": "WITH_ERRORS", "networkImpacts": [ { - "impactType": "CREATION", - "elementId": "lineId", + "type": "SIMPLE", "elementType": "LINE", + "simpleImpactType": "CREATION", + "elementId": "lineId", "substationIds": [ "s1", "s2" ] }, { - "impactType": "MODIFICATION", - "elementId": "loadId", + "type": "SIMPLE", "elementType": "LOAD", + "simpleImpactType": "MODIFICATION", + "elementId": "loadId", "substationIds": [ "s3" ] }, { - "impactType": "DELETION", - "elementId": "generatorId", + "type": "SIMPLE", "elementType": "GENERATOR", + "simpleImpactType": "DELETION", + "elementId": "generatorId", "substationIds": [ "s4" ] @@ -34,4 +37,4 @@ "s3", "s4" ] -} \ No newline at end of file +} diff --git a/src/test/resources/network-modification-result-with-with-warnings.json b/src/test/resources/network-modification-result-with-with-warnings.json index cf9253f7c..8adfc5143 100644 --- a/src/test/resources/network-modification-result-with-with-warnings.json +++ b/src/test/resources/network-modification-result-with-with-warnings.json @@ -3,26 +3,29 @@ "lastGroupApplicationStatus": "WITH_WARNINGS", "networkImpacts": [ { - "impactType": "CREATION", - "elementId": "lineId", + "type": "SIMPLE", "elementType": "LINE", + "simpleImpactType": "CREATION", + "elementId": "lineId", "substationIds": [ "s1", "s2" ] }, { - "impactType": "MODIFICATION", - "elementId": "loadId", + "type": "SIMPLE", "elementType": "LOAD", + "simpleImpactType": "MODIFICATION", + "elementId": "loadId", "substationIds": [ "s3" ] }, { - "impactType": "DELETION", - "elementId": "generatorId", + "type": "SIMPLE", "elementType": "GENERATOR", + "simpleImpactType": "DELETION", + "elementId": "generatorId", "substationIds": [ "s4" ] @@ -34,4 +37,4 @@ "s3", "s4" ] -} \ No newline at end of file +}