From 0d0c8675422c2fff406305de0f6a7370622fc6db Mon Sep 17 00:00:00 2001 From: sBouzols Date: Tue, 12 May 2026 22:26:54 +0200 Subject: [PATCH 1/3] feat(): Add POST "/results/statuses" endpoint to get multiple statuses at once given a collection of resultUuids in body Signed-off-by: sBouzols --- pom.xml | 3 +++ .../server/SecurityAnalysisController.java | 8 ++++++++ .../repositories/SecurityAnalysisResultRepository.java | 2 ++ .../server/service/SecurityAnalysisResultService.java | 9 +++++++++ 4 files changed, 22 insertions(+) diff --git a/pom.xml b/pom.xml index d7911ecb..77efdaad 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,8 @@ 5.0.0-alpha.14 gridsuite org.gridsuite:security-analysis-server + + 2.3.0-SNAPSHOT @@ -175,6 +177,7 @@ org.gridsuite gridsuite-computation + ${gridsuite-computation.version} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java index 73edbb29..db3b10c6 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisController.java @@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Map; import java.util.UUID; import static org.gridsuite.computation.service.NotificationService.HEADER_USER_ID; @@ -270,6 +271,13 @@ public ResponseEntity getStatus(@Parameter(description = return ResponseEntity.ok().body(result); } + @PostMapping(value = "/results/statuses", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Get the security analysis statuses from the database") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis statuses")}) + public ResponseEntity> getStatuses(@Parameter(description = "Result uuids") @RequestBody List resultUuids) { + return ResponseEntity.ok().body(securityAnalysisService.getStatuses(resultUuids)); + } + @PutMapping(value = "/results/invalidate-status", produces = APPLICATION_JSON_VALUE) @Operation(summary = "Invalidate the security analysis status from the database") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis status has been invalidated")}) diff --git a/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java b/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java index 22eec965..6c7c3d35 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java @@ -10,6 +10,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.UUID; /** * @author Kevin Le Saulnier @@ -17,4 +18,5 @@ @Repository public interface SecurityAnalysisResultRepository extends JpaRepository { + List findByResultUuidIn(List resultUuids); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java index 94a03cb6..aabfe2f5 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java @@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import java.util.stream.Collectors; import static org.gridsuite.computation.error.ComputationBusinessErrorCode.INVALID_SORT_FORMAT; import static org.gridsuite.computation.error.ComputationBusinessErrorCode.RESULT_NOT_FOUND; @@ -299,6 +300,14 @@ public SecurityAnalysisStatus findStatus(UUID resultUuid) { return securityAnalysisResult.get().getStatus(); } + @Override + @Transactional(readOnly = true) + public Map findStatuses(List resultUuids) { + Objects.requireNonNull(resultUuids); + List globalEntities = securityAnalysisResultRepository.findByResultUuidIn(resultUuids); + return globalEntities.stream().collect(Collectors.toMap(SecurityAnalysisResultEntity::getId, e -> e.getStatus())); + } + private static Page emptyPage(Pageable pageable) { return new PageImpl<>(List.of(), pageable, 0); } From 0803428e1707037a786e6e6b64936ff43dbe2d6c Mon Sep 17 00:00:00 2001 From: sBouzols Date: Wed, 13 May 2026 10:41:52 +0200 Subject: [PATCH 2/3] fix error Co-authored-by: Copilot Signed-off-by: sBouzols --- .../server/repositories/SecurityAnalysisResultRepository.java | 2 -- .../server/service/SecurityAnalysisResultService.java | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java b/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java index 6c7c3d35..22eec965 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/repositories/SecurityAnalysisResultRepository.java @@ -10,7 +10,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.List; import java.util.UUID; /** * @author Kevin Le Saulnier @@ -18,5 +17,4 @@ @Repository public interface SecurityAnalysisResultRepository extends JpaRepository { - List findByResultUuidIn(List resultUuids); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java index aabfe2f5..5348d130 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java @@ -304,8 +304,8 @@ public SecurityAnalysisStatus findStatus(UUID resultUuid) { @Transactional(readOnly = true) public Map findStatuses(List resultUuids) { Objects.requireNonNull(resultUuids); - List globalEntities = securityAnalysisResultRepository.findByResultUuidIn(resultUuids); - return globalEntities.stream().collect(Collectors.toMap(SecurityAnalysisResultEntity::getId, e -> e.getStatus())); + List saResultEntities = securityAnalysisResultRepository.findAllById(resultUuids); + return saResultEntities.stream().collect(Collectors.toMap(SecurityAnalysisResultEntity::getId, SecurityAnalysisResultEntity::getStatus)); } private static Page emptyPage(Pageable pageable) { From c61cad3e3d86a364b3a752bb5e2925a859598c93 Mon Sep 17 00:00:00 2001 From: sBouzols Date: Wed, 13 May 2026 10:42:12 +0200 Subject: [PATCH 3/3] test(): Add TU for /statuses Co-authored-by: Copilot Signed-off-by: sBouzols --- .../SecurityAnalysisControllerTest.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java index 63ab1362..65bfaa0b 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java @@ -671,6 +671,40 @@ void testStatus() throws Exception { assertEquals(SecurityAnalysisStatus.NOT_DONE, securityAnalysisStatus); } + @Test + void testStatuses() throws Exception { + MvcResult mvcResult; + String resultAsString; + + mvcResult = mockMvc.perform(post("/" + VERSION + "/networks/" + NETWORK_UUID + "/run-and-save?reportType=SecurityAnalysis&loadFlowParametersUuid=" + UUID.randomUUID()) + .header(HEADER_USER_ID, USER_ID) + .contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON) + ).andReturn(); + + resultAsString = mvcResult.getResponse().getContentAsString(); + UUID resultUuid = mapper.readValue(resultAsString, UUID.class); + assertEquals(RESULT_UUID, resultUuid); + + output.receive(TIMEOUT, "sa.result"); + + UUID unknownResultUuid = UUID.randomUUID(); + mvcResult = mockMvc.perform(post("/" + VERSION + "/results/statuses") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(List.of(resultUuid, unknownResultUuid)))) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON) + ).andReturn(); + + Map statuses = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); + assertEquals(1, statuses.size()); + assertEquals(SecurityAnalysisStatus.CONVERGED, statuses.get(resultUuid)); + assertFalse(statuses.containsKey(unknownResultUuid)); + } + @Test void stopTest() throws Exception { countDownLatch = new CountDownLatch(1);