From 784651946e73e3492e9eb9d086aede844e59561b Mon Sep 17 00:00:00 2001 From: achour94 Date: Thu, 13 Nov 2025 14:57:49 +0100 Subject: [PATCH] Enhance report handling and inheritance in modification processing Signed-off-by: achour94 --- .../study/server/dto/BuildInfos.java | 43 ++++++++ .../study/server/dto/ReportInfos.java | 7 +- .../study/server/dto/ReportMode.java | 16 +++ .../RootNetworkNodeInfoRepository.java | 50 +++++++++ .../NetworkModificationTreeService.java | 101 +++++++++++++++++- .../service/RootNetworkNodeInfoService.java | 78 +++++++++++++- .../study/server/service/StudyService.java | 40 ++++--- .../server/ModificationIndexationTest.java | 8 +- .../study/server/NetworkModificationTest.java | 3 +- .../org/gridsuite/study/server/StudyTest.java | 16 +-- .../DynamicSimulationServiceTest.java | 7 +- 11 files changed, 327 insertions(+), 42 deletions(-) create mode 100644 src/main/java/org/gridsuite/study/server/dto/ReportMode.java diff --git a/src/main/java/org/gridsuite/study/server/dto/BuildInfos.java b/src/main/java/org/gridsuite/study/server/dto/BuildInfos.java index acb31910cd..6dcda5284c 100644 --- a/src/main/java/org/gridsuite/study/server/dto/BuildInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/BuildInfos.java @@ -30,8 +30,19 @@ public class BuildInfos { // map with modification groups as key, modification to excludes as value private Map> modificationUuidsToExclude = new HashMap<>(); + /** + * Reports generated during this build operation. + * These are new reports created when applying modifications. + */ private List reportsInfos = new ArrayList<>(); + /** + * Reports inherited from the nearest built parent node. + * These ensure child nodes maintain references to ancestor reports, + * preventing premature deletion when intermediate nodes are unbuilt. + */ + private List inheritedReportsInfos = new ArrayList<>(); + public void insertModificationInfos(UUID modificationGroupUuid, Set modificationUuidsToExclude, ReportInfos reportInfos) { if (modificationUuidsToExclude != null && !modificationUuidsToExclude.isEmpty()) { this.modificationUuidsToExclude.put(modificationGroupUuid, modificationUuidsToExclude); @@ -39,4 +50,36 @@ public void insertModificationInfos(UUID modificationGroupUuid, Set modifi modificationGroupUuids.add(0, modificationGroupUuid); reportsInfos.add(0, reportInfos); } + + /** + * Adds a report inherited from a built parent node. + * Inherited reports are added at the end to maintain proper ordering: + * parent reports come before child reports. + * + * @param nodeUuid The UUID of the node that owns this report + * @param reportUuid The UUID of the report + */ + public void addInheritedReport(UUID nodeUuid, UUID reportUuid) { + inheritedReportsInfos.add(new ReportInfos(reportUuid, nodeUuid)); + } + + /** + * Gets all reports (both new and inherited) as a single map. + * Useful for storing the complete report set in the database. + * + * @return Map of node UUID to report UUID + */ + public Map getAllReportsAsMap() { + Map allReports = new LinkedHashMap<>(); + + // Add inherited reports first (parent reports come first) + inheritedReportsInfos.forEach(r -> + allReports.put(r.nodeUuid(), r.reportUuid())); + + // Add new reports (may override inherited if same node) + reportsInfos.forEach(r -> + allReports.put(r.nodeUuid(), r.reportUuid())); + + return allReports; + } } diff --git a/src/main/java/org/gridsuite/study/server/dto/ReportInfos.java b/src/main/java/org/gridsuite/study/server/dto/ReportInfos.java index b5426d0ee7..e7c65899a8 100644 --- a/src/main/java/org/gridsuite/study/server/dto/ReportInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/ReportInfos.java @@ -16,8 +16,11 @@ @Schema(description = "Report infos") public record ReportInfos( UUID reportUuid, - UUID nodeUuid + UUID nodeUuid, + ReportMode reportMode ) { - + public ReportInfos(UUID reportUuid, UUID nodeUuid) { + this(reportUuid, nodeUuid, ReportMode.APPEND); + } } diff --git a/src/main/java/org/gridsuite/study/server/dto/ReportMode.java b/src/main/java/org/gridsuite/study/server/dto/ReportMode.java new file mode 100644 index 0000000000..44a0c06a5d --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/dto/ReportMode.java @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.study.server.dto; + +/** + * Enum to specify how reports should be handled when building nodes. + * @author Achour BERRAHMA + */ +public enum ReportMode { + APPEND, + REPLACE +} diff --git a/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java b/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java index 79c1bd9329..61919ef07b 100644 --- a/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java +++ b/src/main/java/org/gridsuite/study/server/repository/rootnetwork/RootNetworkNodeInfoRepository.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; /** @@ -65,4 +66,53 @@ public interface RootNetworkNodeInfoRepository extends JpaRepository nodesUuids); + + /** + * Finds report UUIDs that are still referenced by other RootNetworkNodeInfo entities. + *

+ * This is a critical safety query that prevents cascade deletion of shared reports. + * It performs a bulk check in a single database round trip for efficiency. + *

+ * Use case: When invalidating a node, we need to determine which + * reports can be safely deleted. This query identifies reports that are still needed + * by other nodes. + * + * @param reportUuids Set of report UUIDs to check for references + * @param excludedEntityId The RootNetworkNodeInfo ID to exclude from the check + * (typically the node being deleted/invalidated) + * @return Set of report UUIDs that are still referenced by other entities + */ + @Query(""" + SELECT DISTINCT VALUE(rnni.modificationReports) + FROM RootNetworkNodeInfoEntity rnni + JOIN rnni.modificationReports mr + WHERE VALUE(rnni.modificationReports) IN :reportUuids + AND rnni.id != :excludedEntityId + """) + Set findReferencedReportUuidsExcludingEntity(Set reportUuids, UUID excludedEntityId); + + /** + * Finds report UUIDs for a specific node by searching across all RootNetworkNodeInfo + * entities in the given root network. + *

+ * This method searches the modificationReports maps of all nodes in the root network + * to find if any node has already generated a report for the target node. + *

+ * Important: Based on our code logic, there should be at most one report UUID + * assigned to any given node across the entire root network. The returned Set should contain + * either 0 or 1 elements. If the Set contains multiple values, this indicates a data + * inconsistency that should be investigated. + * + * @param targetNodeUuid the node UUID to find a report for (the map key) + * @param rootNetworkUuid the root network to search within + * @return a Set containing the report UUID(s) found in the modificationReports maps, + * expected to be empty or contain exactly one element under normal conditions + */ + @Query(""" + SELECT DISTINCT VALUE(rnni.modificationReports) + FROM RootNetworkNodeInfoEntity rnni + WHERE rnni.rootNetwork.id = :rootNetworkUuid + AND KEY(rnni.modificationReports) = :targetNodeUuid + """) + Set findReportUuidsForNodeInRootNetwork(UUID targetNodeUuid, UUID rootNetworkUuid); } diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java index da77939930..8fe7ed1326 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java @@ -747,12 +747,17 @@ public boolean hasModifications(@NonNull UUID nodeUuid, boolean stashed) { } @Transactional - public UUID getReportUuid(UUID nodeUuid, UUID rootNetworkUuid) { + public Optional getReportUuid(UUID nodeUuid, UUID rootNetworkUuid) { NodeEntity nodeEntity = getNodeEntity(nodeUuid); if (nodeEntity.getType().equals(NodeType.ROOT)) { - return rootNetworkService.getRootReportUuid(rootNetworkUuid); + return Optional.ofNullable(rootNetworkService.getRootReportUuid(rootNetworkUuid)); } else { - return rootNetworkNodeInfoService.getRootNetworkNodeInfo(nodeUuid, rootNetworkUuid).orElseThrow(() -> new StudyException(ROOT_NETWORK_NOT_FOUND)).getModificationReports().get(nodeUuid); + return Optional.ofNullable( + rootNetworkNodeInfoService.getRootNetworkNodeInfo(nodeUuid, rootNetworkUuid) + .orElseThrow(() -> new StudyException(ROOT_NETWORK_NOT_FOUND)) + .getModificationReports() + .get(nodeUuid) + ); } } @@ -846,10 +851,94 @@ public List getAllNodes(UUID studyUuid) { return nodesRepository.findAllByStudyId(studyUuid); } + /** + * Gets or generates a modification report UUID for a node. + *

+ * Search priority: + * 1. Check if the node being built already has a report for this node + * 2. Search across ALL nodes in the root network for existing reports + * 3. Generate a new UUID if not found anywhere + *

+ * This implements intelligent report reuse to avoid duplicate reports when + * multiple nodes are built in different orders. + * + * @param nodeUuid the node that needs a report + * @param rootNetworkUuid the root network context + * @param nodeToBuildUuid the node currently being built + * @return the report UUID to use (existing or new) + */ private UUID getModificationReportUuid(UUID nodeUuid, UUID rootNetworkUuid, UUID nodeToBuildUuid) { - return self.getModificationReports(nodeToBuildUuid, rootNetworkUuid).getOrDefault(nodeUuid, UUID.randomUUID()); + Map targetNodeReports = self.getModificationReports(nodeToBuildUuid, rootNetworkUuid); + if (targetNodeReports.containsKey(nodeUuid)) { + return targetNodeReports.get(nodeUuid); + } + + Optional crossNodeReportUuid = rootNetworkNodeInfoService + .findExistingReportUuidForNode(nodeUuid, rootNetworkUuid); + + return crossNodeReportUuid.orElseGet(UUID::randomUUID); } + /** + * Inherits modification reports from the nearest built ancestor node. + *

+ * When building a node, we inherit all report references from its nearest built parent. + * This ensures that if an intermediate node is later deleted, reports referenced by + * descendant nodes won't be accidentally deleted. + *

+ * Example node tree: + *

+     * ROOT (built)
+     *   └─ N1 (not built, report: r1)
+     *      └─ N2 (built, reports: {N1→r1, N2→r2})
+     *         └─ N3 (not built, report: r3)
+     *            └─ N4 (building, report: r4)
+     *
+     * When N4 builds:
+     * 1. Finds N2 as nearest built parent
+     * 2. Inherits {N1→r1, N2→r2} from N2
+     * 3. Adds its own {N3→r3, N4→r4}
+     * 4. Final reports: {N1→r1, N2→r2, N3→r3, N4→r4}
+     *
+     * If N2 is later deleted, reports r1 and r2 won't be deleted
+     * because N4 still references them.
+     * 
+ * + * @param builtParentNodeUuid UUID of the built parent node + * @param rootNetworkUuid Root network context + * @param buildInfos Build information to populate with inherited reports + */ + private void inheritModificationReportsFromBuiltParent(UUID builtParentNodeUuid, UUID rootNetworkUuid, BuildInfos buildInfos) { + Map parentReports = self.getModificationReports( + builtParentNodeUuid, + rootNetworkUuid + ); + + if (parentReports == null || parentReports.isEmpty()) { + return; + } + + Set alreadyCollectedNodes = buildInfos.getReportsInfos().stream() + .map(ReportInfos::nodeUuid) + .collect(Collectors.toSet()); + + parentReports.entrySet().stream() + .filter(entry -> !alreadyCollectedNodes.contains(entry.getKey())) + .forEach(entry -> buildInfos.addInheritedReport( + entry.getKey(), + entry.getValue() + )); + } + + /** + * Recursively collects build information by traversing up the node tree. + * Stops at the first built parent and inherits its reports. + * + * @param nodeEntity Current node being processed + * @param rootNetworkUuid Root network context + * @param buildInfos Accumulator for build information + * @param nodeToBuildUuid The target node being built + */ private void getBuildInfos(NodeEntity nodeEntity, UUID rootNetworkUuid, BuildInfos buildInfos, UUID nodeToBuildUuid) { AbstractNode node = getSimpleNode(nodeEntity.getIdNode()); if (node.getType() == NodeType.NETWORK_MODIFICATION) { @@ -857,10 +946,12 @@ private void getBuildInfos(NodeEntity nodeEntity, UUID rootNetworkUuid, BuildInf RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity = rootNetworkNodeInfoService.getRootNetworkNodeInfo(nodeEntity.getIdNode(), rootNetworkUuid).orElseThrow(() -> new StudyException(ROOT_NETWORK_NOT_FOUND)); if (!rootNetworkNodeInfoEntity.getNodeBuildStatus().toDto().isBuilt()) { UUID reportUuid = getModificationReportUuid(nodeEntity.getIdNode(), rootNetworkUuid, nodeToBuildUuid); - buildInfos.insertModificationInfos(modificationNode.getModificationGroupUuid(), rootNetworkNodeInfoEntity.getModificationsUuidsToExclude(), new ReportInfos(reportUuid, modificationNode.getId())); + ReportInfos reportInfos = new ReportInfos(reportUuid, modificationNode.getId(), ReportMode.REPLACE); + buildInfos.insertModificationInfos(modificationNode.getModificationGroupUuid(), rootNetworkNodeInfoEntity.getModificationsUuidsToExclude(), reportInfos); getBuildInfos(nodeEntity.getParentNode(), rootNetworkUuid, buildInfos, nodeToBuildUuid); } else { buildInfos.setOriginVariantId(self.getVariantId(nodeEntity.getIdNode(), rootNetworkUuid)); + inheritModificationReportsFromBuiltParent(nodeEntity.getIdNode(), rootNetworkUuid, buildInfos); } } } diff --git a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java index b0d3361375..abe6a0395c 100644 --- a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java +++ b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java @@ -255,7 +255,7 @@ public InvalidateNodeInfos invalidateRootNetworkNode(RootNetworkNodeInfoEntity r InvalidateNodeInfos invalidateNodeInfos = getInvalidationComputationInfos(rootNetworkNodeInfoEntity, invalidateTreeParameters.computationsInvalidationMode()); if (notOnlyChildrenBuildStatus) { - rootNetworkNodeInfoEntity.getModificationReports().forEach((key, value) -> invalidateNodeInfos.addReportUuid(value)); + collectDeletableReports(rootNetworkNodeInfoEntity, invalidateNodeInfos); invalidateNodeInfos.addVariantId(rootNetworkNodeInfoEntity.getVariantId()); invalidateBuildStatus(rootNetworkNodeInfoEntity, invalidateNodeInfos); } @@ -265,10 +265,84 @@ public InvalidateNodeInfos invalidateRootNetworkNode(RootNetworkNodeInfoEntity r return invalidateNodeInfos; } + /** + * Finds an existing report UUID for a node by searching across all nodes + * in the same root network. + * + * @param targetNodeUuid the node to find a report for + * @param rootNetworkUuid the root network context + * @return Optional containing the report UUID if found anywhere, empty otherwise + */ + @Transactional(readOnly = true) + public Optional findExistingReportUuidForNode(UUID targetNodeUuid, UUID rootNetworkUuid) { + Set reportUuids = rootNetworkNodeInfoRepository.findReportUuidsForNodeInRootNetwork(targetNodeUuid, rootNetworkUuid); + if (reportUuids.isEmpty()) { + return Optional.empty(); + } + // We assume that there is only one report UUID for a given node across all nodes in the same root network, + // so we return the first one found + return Optional.of(reportUuids.iterator().next()); + } + + /** + * Identifies and collects report UUIDs that can be safely deleted. + *

+ * Only reports that are exclusively owned by the specified entity + * will be marked for deletion. Reports shared with other nodes are preserved. + * + * @param rootNetworkNodeInfo The entity being invalidated + * @param invalidateNodeInfos Accumulator for deletion candidates + */ + private void collectDeletableReports( + RootNetworkNodeInfoEntity rootNetworkNodeInfo, + InvalidateNodeInfos invalidateNodeInfos) { + + Map nodeReports = rootNetworkNodeInfo.getModificationReports(); + + if (nodeReports == null || nodeReports.isEmpty()) { + return; + } + + Set candidateReportUuids = new HashSet<>(nodeReports.values()); + + Set safeToDelete = filterForExclusivelyOwnedReports( + candidateReportUuids, + rootNetworkNodeInfo.getId() + ); + + safeToDelete.forEach(invalidateNodeInfos::addReportUuid); + } + + /** + * Filters report UUIDs to only include those not referenced by other nodes. + *

+ * This safety mechanism prevents cascade deletion of shared reports. + * Uses a database query to check all report references in a single round trip. + * + * @param candidateReportUuids Report UUIDs being considered for deletion + * @param ownerEntityId ID of the entity being processed + * @return Set of reports that can be safely deleted (not referenced elsewhere) + */ + private Set filterForExclusivelyOwnedReports( + Set candidateReportUuids, + UUID ownerEntityId) { + + if (candidateReportUuids.isEmpty()) { + return Collections.emptySet(); + } + + Set sharedReports = rootNetworkNodeInfoRepository + .findReferencedReportUuidsExcludingEntity(candidateReportUuids, ownerEntityId); + + return candidateReportUuids.stream() + .filter(reportUuid -> !sharedReports.contains(reportUuid)) + .collect(Collectors.toSet()); + } + private static void invalidateBuildStatus(RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity, InvalidateNodeInfos invalidateNodeInfos) { rootNetworkNodeInfoEntity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.NOT_BUILT)); rootNetworkNodeInfoEntity.setVariantId(UUID.randomUUID().toString()); - rootNetworkNodeInfoEntity.setModificationReports(new HashMap<>(Map.of(rootNetworkNodeInfoEntity.getNodeInfo().getId(), UUID.randomUUID()))); + rootNetworkNodeInfoEntity.setModificationReports(new HashMap<>()); invalidateNodeInfos.addNodeUuid(rootNetworkNodeInfoEntity.getNodeInfo().getIdNode()); } diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index e2a274b4f3..4455f5c765 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -1823,8 +1823,9 @@ public void buildNode(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull private void buildNode(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull UUID rootNetworkUuid, @NonNull String userId, AbstractWorkflowInfos workflowInfos) { assertCanBuildNode(studyUuid, rootNetworkUuid, userId); BuildInfos buildInfos = networkModificationTreeService.getBuildInfos(nodeUuid, rootNetworkUuid); - Map nodeUuidToReportUuid = buildInfos.getReportsInfos().stream().collect(Collectors.toMap(ReportInfos::nodeUuid, ReportInfos::reportUuid)); - networkModificationTreeService.setModificationReports(nodeUuid, rootNetworkUuid, nodeUuidToReportUuid); + + // Store all reports (inherited + new) for this node + networkModificationTreeService.setModificationReports(nodeUuid, rootNetworkUuid, buildInfos.getAllReportsAsMap()); networkModificationTreeService.updateNodeBuildStatus(nodeUuid, rootNetworkUuid, NodeBuildStatus.from(BuildStatus.BUILDING)); try { networkModificationService.buildNode(nodeUuid, rootNetworkUuid, buildInfos, workflowInfos); @@ -2419,9 +2420,10 @@ private ReportPage getParentNodesReportLogs(UUID nodeUuid, UUID rootNetworkUuid, Map modificationReportsMap = networkModificationTreeService.getModificationReports(nodeUuid, rootNetworkUuid); List reportUuids = nodeIds.stream() - .map(nodeId -> modificationReportsMap.getOrDefault(nodeId, - networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid))) - .filter(Objects::nonNull) + .map(nodeId -> Optional.ofNullable(modificationReportsMap.get(nodeId)) + .or(() -> networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid))) + .filter(Optional::isPresent) + .map(Optional::get) .toList(); return reportService.getPagedMultipleReportLogs(reportUuids, messageFilter, severityLevels, paged, pageable); } @@ -2439,9 +2441,10 @@ private String getSearchTermMatchesInParentNodesFilteredLogs(UUID nodeUuid, UUID Map modificationReportsMap = networkModificationTreeService.getModificationReports(nodeUuid, rootNetworkUuid); List reportUuids = nodeIds.stream() - .map(nodeId -> modificationReportsMap.getOrDefault(nodeId, - networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid))) - .filter(Objects::nonNull) + .map(nodeId -> Optional.ofNullable(modificationReportsMap.get(nodeId)) + .or(() -> networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid))) + .filter(Optional::isPresent) + .map(Optional::get) .toList(); return reportService.getSearchTermMatchesInMultipleFilteredLogs(reportUuids, severityLevels, messageFilter, searchTerm, pageSize); } @@ -2460,8 +2463,12 @@ private Set getParentNodesAggregatedReportSeverities(UUID nodeUuid, UUID Map modificationReportsMap = networkModificationTreeService.getModificationReports(nodeUuid, rootNetworkUuid); for (UUID nodeId : nodeIds) { - UUID reportId = modificationReportsMap.getOrDefault(nodeId, networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid)); - severities.addAll(reportService.getReportAggregatedSeverities(reportId)); + Optional reportId = Optional.ofNullable(modificationReportsMap.get(nodeId)) + .or(() -> networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid)); + + reportId.ifPresent(uuid -> + severities.addAll(reportService.getReportAggregatedSeverities(uuid)) + ); } return severities; } @@ -2497,8 +2504,9 @@ private UUID getReportUuidForNode(UUID nodeUuid, UUID rootNetworkUuid, ReportTyp } private List getNodeOnlyReport(UUID nodeUuid, UUID rootNetworkUuid, Set severityLevels) { - UUID reportUuid = networkModificationTreeService.getReportUuid(nodeUuid, rootNetworkUuid); - return List.of(reportService.getReport(reportUuid, nodeUuid.toString(), severityLevels)); + return networkModificationTreeService.getReportUuid(nodeUuid, rootNetworkUuid) + .map(uuid -> List.of(reportService.getReport(uuid, nodeUuid.toString(), severityLevels))) + .orElse(Collections.emptyList()); } private List getAllModificationReports(UUID nodeUuid, UUID rootNetworkUuid, Set severityLevels) { @@ -2507,8 +2515,12 @@ private List getAllModificationReports(UUID nodeUuid, UUID rootNetworkUu Map modificationReportsMap = networkModificationTreeService.getModificationReports(nodeUuid, rootNetworkUuid); for (UUID nodeId : nodeIds) { - UUID reportId = modificationReportsMap.getOrDefault(nodeId, networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid)); - modificationReports.add(reportService.getReport(reportId, nodeId.toString(), severityLevels)); + Optional reportId = Optional.ofNullable(modificationReportsMap.get(nodeId)) + .or(() -> networkModificationTreeService.getReportUuid(nodeId, rootNetworkUuid)); + + reportId.ifPresent(uuid -> + modificationReports.add(reportService.getReport(uuid, nodeId.toString(), severityLevels)) + ); } return modificationReports; diff --git a/src/test/java/org/gridsuite/study/server/ModificationIndexationTest.java b/src/test/java/org/gridsuite/study/server/ModificationIndexationTest.java index 12e3c42f8f..e45d543d7c 100644 --- a/src/test/java/org/gridsuite/study/server/ModificationIndexationTest.java +++ b/src/test/java/org/gridsuite/study/server/ModificationIndexationTest.java @@ -94,7 +94,7 @@ void testInvalidateBuiltNodeAndItsChildren() { node3.getModificationGroupUuid() )); - SQLStatementCountValidator.assertSelectCount(17); + SQLStatementCountValidator.assertSelectCount(18); } @Test @@ -106,7 +106,7 @@ void testInvalidateNotBuiltNodeAndItsChildren() { node5.getModificationGroupUuid() )); - SQLStatementCountValidator.assertSelectCount(17); + SQLStatementCountValidator.assertSelectCount(18); } @Test @@ -117,7 +117,7 @@ void testInvalidateBuiltNodeChildrenOnly() { node5.getModificationGroupUuid() )); - SQLStatementCountValidator.assertSelectCount(8); + SQLStatementCountValidator.assertSelectCount(9); } @Test @@ -129,7 +129,7 @@ void testInvalidateNotBuiltNodeChildrenOnly() { node3.getModificationGroupUuid() )); - SQLStatementCountValidator.assertSelectCount(17); + SQLStatementCountValidator.assertSelectCount(18); } @Test diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java index ab28785f94..a5a4dfa0af 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java @@ -2505,8 +2505,7 @@ void testNodesInvalidation(final MockWebServer server) throws Exception { Pair> modificationBody = Pair.of(jsonCreateLoadInfos, List.of(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(firstRootNetworkUuid, modificationNode2Uuid, NETWORK_UUID))); wireMockUtils.verifyNetworkModificationPostWithVariant(stubPostId, getModificationContextJsonString(mapper, modificationBody)); - requests = TestUtils.getRequestsWithBodyDone(1, server); - assertEquals(1, requests.stream().filter(r -> r.getPath().matches("/v1/reports")).count()); + TestUtils.assertServerRequestsEmptyThenShutdown(server); } @Test diff --git a/src/test/java/org/gridsuite/study/server/StudyTest.java b/src/test/java/org/gridsuite/study/server/StudyTest.java index 9b6901e08b..9826f08d49 100644 --- a/src/test/java/org/gridsuite/study/server/StudyTest.java +++ b/src/test/java/org/gridsuite/study/server/StudyTest.java @@ -1222,10 +1222,10 @@ void testGetSearchTermMatchesInMultipleFilteredLogs(final MockWebServer server) AbstractNode modificationNode = rootNode.getChildren().get(0); NetworkModificationNode node1 = createNetworkModificationNode(studyUuid, modificationNodeUuid, VARIANT_ID, "node1", userId); NetworkModificationNode node2 = createNetworkModificationNode(studyUuid, node1.getId(), VARIANT_ID_2, "node2", userId); - UUID rootNodeReportId = networkModificationTreeService.getReportUuid(rootNode.getId(), firstRootNetworkUuid); - UUID modificationNodeReportId = networkModificationTreeService.getReportUuid(modificationNode.getId(), firstRootNetworkUuid); - UUID node1ReportId = networkModificationTreeService.getReportUuid(node1.getId(), firstRootNetworkUuid); - UUID node2ReportId = networkModificationTreeService.getReportUuid(node2.getId(), firstRootNetworkUuid); + UUID rootNodeReportId = networkModificationTreeService.getReportUuid(rootNode.getId(), firstRootNetworkUuid).orElseThrow(); + UUID modificationNodeReportId = networkModificationTreeService.getReportUuid(modificationNode.getId(), firstRootNetworkUuid).orElseThrow(); + UUID node1ReportId = networkModificationTreeService.getReportUuid(node1.getId(), firstRootNetworkUuid).orElseThrow(); + UUID node2ReportId = networkModificationTreeService.getReportUuid(node2.getId(), firstRootNetworkUuid).orElseThrow(); mockMvc.perform(get("/v1/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/report/logs/search?searchTerm=testTerm&pageSize=10&severityLevels=WARN&message=testMsgFilter", studyUuid, firstRootNetworkUuid, node2.getId()).header(USER_ID_HEADER, "userId")) .andExpect(status().isOk()); @@ -1243,10 +1243,10 @@ void testGetParentNodesReportLogs(final MockWebServer server) throws Exception { NetworkModificationNode node1 = createNetworkModificationNode(studyUuid, modificationNodeUuid, VARIANT_ID, "node1", userId); NetworkModificationNode node2 = createNetworkModificationNode(studyUuid, node1.getId(), VARIANT_ID_2, "node2", userId); createNetworkModificationNode(studyUuid, modificationNodeUuid, VARIANT_ID_3, "node3", userId); - UUID rootNodeReportId = networkModificationTreeService.getReportUuid(rootNode.getId(), firstRootNetworkUuid); - UUID modificationNodeReportId = networkModificationTreeService.getReportUuid(modificationNode.getId(), firstRootNetworkUuid); - UUID node1ReportId = networkModificationTreeService.getReportUuid(node1.getId(), firstRootNetworkUuid); - UUID node2ReportId = networkModificationTreeService.getReportUuid(node2.getId(), firstRootNetworkUuid); + UUID rootNodeReportId = networkModificationTreeService.getReportUuid(rootNode.getId(), firstRootNetworkUuid).orElseThrow(); + UUID modificationNodeReportId = networkModificationTreeService.getReportUuid(modificationNode.getId(), firstRootNetworkUuid).orElseThrow(); + UUID node1ReportId = networkModificationTreeService.getReportUuid(node1.getId(), firstRootNetworkUuid).orElseThrow(); + UUID node2ReportId = networkModificationTreeService.getReportUuid(node2.getId(), firstRootNetworkUuid).orElseThrow(); // root // | diff --git a/src/test/java/org/gridsuite/study/server/service/dynamicsimulation/DynamicSimulationServiceTest.java b/src/test/java/org/gridsuite/study/server/service/dynamicsimulation/DynamicSimulationServiceTest.java index 74a156c164..0bc75e3fee 100644 --- a/src/test/java/org/gridsuite/study/server/service/dynamicsimulation/DynamicSimulationServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/service/dynamicsimulation/DynamicSimulationServiceTest.java @@ -37,10 +37,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.stream.LongStream; import static org.assertj.core.api.Assertions.assertThat; @@ -142,7 +139,7 @@ void setup() { void testRunDynamicSimulation() { given(rootNetworkService.getNetworkUuid(ROOTNETWORK_UUID)).willReturn(NETWORK_UUID); given(networkModificationTreeService.getVariantId(NODE_UUID, ROOTNETWORK_UUID)).willReturn(VARIANT_1_ID); - given(networkModificationTreeService.getReportUuid(NODE_UUID, ROOTNETWORK_UUID)).willReturn(REPORT_UUID); + given(networkModificationTreeService.getReportUuid(NODE_UUID, ROOTNETWORK_UUID)).willReturn(Optional.of(REPORT_UUID)); // setup DynamicSimulationClient mock given(dynamicSimulationClient.run(eq(""), any(), eq(NETWORK_UUID), eq(VARIANT_1_ID), eq(new ReportInfos(REPORT_UUID, NODE_UUID)), any(), any(), eq(false))).willReturn(RESULT_UUID);