From ea2dc430f2ca4e36c5c99e9087fb2a1ec966e5ae Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Fri, 5 Jan 2024 10:58:33 +0100 Subject: [PATCH 01/18] Export sensitivity results as csv --- .../server/SensitivityAnalysisController.java | 24 +++++++++- .../SensitivityAnalysisResultRepository.java | 22 +++++---- .../service/SensitivityAnalysisService.java | 46 +++++++++++++++++++ .../SensitivityAnalysisServiceTest.java | 20 ++++++++ 4 files changed, 100 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java index 7fc4e2ba..35d16b9b 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java @@ -17,15 +17,16 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; -import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; -import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisInputData; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisStatus; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityResultFilterOptions; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityRunQueryResult; +import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; +import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.service.SensitivityAnalysisRunContext; import org.gridsuite.sensitivityanalysis.server.service.SensitivityAnalysisService; import org.gridsuite.sensitivityanalysis.server.service.SensitivityAnalysisWorkerService; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -36,6 +37,7 @@ import static org.gridsuite.sensitivityanalysis.server.service.NotificationService.HEADER_USER_ID; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM; import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; /** @@ -203,4 +205,22 @@ public ResponseEntity> getProviders() { public ResponseEntity getDefaultProvider() { return ResponseEntity.ok().body(service.getDefaultProvider()); } + + @GetMapping(value = "/results/{resultUuid}/csv") + @Operation(summary = "export sensitivity results as csv file") + @ApiResponses(@ApiResponse(responseCode = "200", description = "Sensitivity results successfully exported as csv file")) + public ResponseEntity exportSensitivityResultsAsCsv(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid, + @RequestParam(name = "selector", required = false) String selectorJson) { + try { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(APPLICATION_OCTET_STREAM); + httpHeaders.setContentDispositionFormData("attachment", "sensitivity_results.csv"); + return ResponseEntity.ok() + .headers(httpHeaders) + .body(service.exportSensitivityResultsAsCsv(resultUuid, getSelector(selectorJson))); + } catch (JsonProcessingException e) { + return ResponseEntity.badRequest().build(); + } + + } } diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java index bf821a57..b6bad100 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java @@ -8,6 +8,8 @@ import com.powsybl.sensitivity.SensitivityAnalysisResult; import com.powsybl.sensitivity.SensitivityValue; +import com.univocity.parsers.csv.CsvWriter; +import com.univocity.parsers.csv.CsvWriterSettings; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.SortKey; @@ -30,6 +32,7 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import java.io.ByteArrayOutputStream; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; @@ -301,15 +304,14 @@ private void complete(SensitivityRunQueryResult.SensitivityRunQueryResultBuilder } private String getSort(SortKey sortKey) { - switch (sortKey) { - case FUNCTION : return "factor.functionId"; - case SENSITIVITY : return "value"; - case REFERENCE : return "functionReference"; - case VARIABLE : return "factor.variableId"; - case CONTINGENCY : return "contingency.contingencyId"; - case POST_REFERENCE : return "functionReferenceAfter"; - case POST_SENSITIVITY : return "valueAfter"; - default: return null; - } + return switch (sortKey) { + case FUNCTION -> "factor.functionId"; + case SENSITIVITY -> "value"; + case REFERENCE -> "functionReference"; + case VARIABLE -> "factor.variableId"; + case CONTINGENCY -> "contingency.contingencyId"; + case POST_REFERENCE -> "functionReferenceAfter"; + case POST_SENSITIVITY -> "valueAfter"; + }; } } diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index 53233625..1e302af1 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -8,6 +8,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.powsybl.sensitivity.SensitivityAnalysisProvider; +import com.univocity.parsers.csv.CsvWriter; +import com.univocity.parsers.csv.CsvWriterSettings; +import org.gridsuite.sensitivityanalysis.server.dto.SensitivityWithContingency; +import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisStatus; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityResultFilterOptions; @@ -17,6 +21,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.io.ByteArrayOutputStream; import java.util.List; import java.util.Objects; import java.util.UUID; @@ -97,4 +102,45 @@ public List getProviders() { public String getDefaultProvider() { return defaultProvider; } + + public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, ResultsSelector selector) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + CsvWriterSettings settings = new CsvWriterSettings(); + CsvWriter csvWriter = new CsvWriter(outputStream, settings); + + SensitivityRunQueryResult result = getRunResult(resultUuid, selector); + if (result == null) { + return null; + } + + if (selector.getTabSelection() == ResultTab.N) { + csvWriter.writeHeaders(List.of("functionId", "variableId", "functionReference", "value")); + result.getSensitivities() + .forEach(sensitivity -> { + csvWriter.writeRow( + sensitivity.getFuncId(), + sensitivity.getVarId(), + sensitivity.getFunctionReference(), + sensitivity.getValue() + ); + }); + } else if (selector.getTabSelection() == ResultTab.N_K) { + csvWriter.writeHeaders(List.of("functionId", "variableId", "contingencyId", "functionReference", "value", "functionReferenceAfter")); + result.getSensitivities() + .forEach(sensitivity -> { + SensitivityWithContingency sensitivityWithContingency = (SensitivityWithContingency) sensitivity; + csvWriter.writeRow( + sensitivityWithContingency.getFuncId(), + sensitivityWithContingency.getVarId(), + sensitivityWithContingency.getContingencyId(), + sensitivityWithContingency.getFunctionReference(), + sensitivityWithContingency.getValue(), + sensitivityWithContingency.getFunctionReferenceAfter() + ); + }); + } + csvWriter.close(); + + return outputStream.toByteArray(); + } } diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index aae09cea..bd83b66f 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -4,7 +4,9 @@ */ package org.gridsuite.sensitivityanalysis.server.service; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -64,6 +66,8 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; @@ -336,6 +340,22 @@ public void testNoNKStillOK() { sensitivities = gottenResult.getSensitivities(); assertThat(sensitivities, not(nullValue())); assertThat(sensitivities.size(), is(0)); + + ResultsSelector exportCsvSelector = ResultsSelector.builder() + .functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) + .tabSelection(ResultTab.N) + .build(); + + var csv = analysisService.exportSensitivityResultsAsCsv(resultUuid, exportCsvSelector); + var csvStr = new String(csv, StandardCharsets.UTF_8); + List actualLines = Arrays.asList(csvStr.split("`\n")); + List expectedLines = new ArrayList<>(List.of("functionId,variableId,functionReference,value", + "l1,GEN,2.9,500.1", + "l2,GEN,2.8,500.2", + "l3,LOAD,2.1,500.9")); + actualLines.sort(String::compareTo); + expectedLines.sort(String::compareTo); + assertEquals(expectedLines, actualLines); } @Test From 80fd047998ab7951126ad9348a38566865e6c1d4 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Mon, 8 Jan 2024 15:52:39 +0100 Subject: [PATCH 02/18] add headers translation --- .../server/SensitivityAnalysisController.java | 14 +++- .../server/dto/CsvFileInputData.java | 17 +++++ .../SensitivityAnalysisResultRepository.java | 3 - .../service/SensitivityAnalysisService.java | 64 ++++++++++--------- .../SensitivityAnalysisServiceTest.java | 7 +- 5 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 src/main/java/org/gridsuite/sensitivityanalysis/server/dto/CsvFileInputData.java diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java index 35d16b9b..e7acea00 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java @@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import org.gridsuite.sensitivityanalysis.server.dto.CsvFileInputData; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisInputData; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisStatus; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityResultFilterOptions; @@ -206,18 +207,25 @@ public ResponseEntity getDefaultProvider() { return ResponseEntity.ok().body(service.getDefaultProvider()); } - @GetMapping(value = "/results/{resultUuid}/csv") + @PostMapping(value = "/results/{resultUuid}/csv") @Operation(summary = "export sensitivity results as csv file") @ApiResponses(@ApiResponse(responseCode = "200", description = "Sensitivity results successfully exported as csv file")) public ResponseEntity exportSensitivityResultsAsCsv(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid, - @RequestParam(name = "selector", required = false) String selectorJson) { + @RequestBody CsvFileInputData csvFileInputData) { try { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(APPLICATION_OCTET_STREAM); httpHeaders.setContentDispositionFormData("attachment", "sensitivity_results.csv"); + byte[] csv = service.exportSensitivityResultsAsCsv(resultUuid, + getSelector(csvFileInputData.getSelector()), + csvFileInputData.getCsvHeaders()); + + if (csv == null) { + return ResponseEntity.notFound().build(); + } return ResponseEntity.ok() .headers(httpHeaders) - .body(service.exportSensitivityResultsAsCsv(resultUuid, getSelector(selectorJson))); + .body(csv); } catch (JsonProcessingException e) { return ResponseEntity.badRequest().build(); } diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/CsvFileInputData.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/CsvFileInputData.java new file mode 100644 index 00000000..aac2bc88 --- /dev/null +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/CsvFileInputData.java @@ -0,0 +1,17 @@ +package org.gridsuite.sensitivityanalysis.server.dto; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@SuperBuilder +@NoArgsConstructor +@Getter +@Setter +public class CsvFileInputData { + private String selector; + private List csvHeaders; +} diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java index b6bad100..072288cb 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/repositories/SensitivityAnalysisResultRepository.java @@ -8,8 +8,6 @@ import com.powsybl.sensitivity.SensitivityAnalysisResult; import com.powsybl.sensitivity.SensitivityValue; -import com.univocity.parsers.csv.CsvWriter; -import com.univocity.parsers.csv.CsvWriterSettings; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.SortKey; @@ -32,7 +30,6 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import java.io.ByteArrayOutputStream; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index 1e302af1..6e16cf0a 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -22,10 +22,14 @@ import org.springframework.stereotype.Service; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** * @author Franck Lecuyer @@ -103,44 +107,46 @@ public String getDefaultProvider() { return defaultProvider; } - public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, ResultsSelector selector) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - CsvWriterSettings settings = new CsvWriterSettings(); - CsvWriter csvWriter = new CsvWriter(outputStream, settings); - + public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, ResultsSelector selector, List headers) { SensitivityRunQueryResult result = getRunResult(resultUuid, selector); if (result == null) { return null; } - if (selector.getTabSelection() == ResultTab.N) { - csvWriter.writeHeaders(List.of("functionId", "variableId", "functionReference", "value")); - result.getSensitivities() - .forEach(sensitivity -> { - csvWriter.writeRow( + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) { + zipOutputStream.putNextEntry(new ZipEntry("sensitivity_result.csv")); + + CsvWriterSettings settings = new CsvWriterSettings(); + CsvWriter csvWriter = new CsvWriter(zipOutputStream, settings); + csvWriter.writeHeaders(headers); + if (selector.getTabSelection() == ResultTab.N) { + result.getSensitivities() + .forEach(sensitivity -> csvWriter.writeRow( sensitivity.getFuncId(), sensitivity.getVarId(), sensitivity.getFunctionReference(), sensitivity.getValue() - ); - }); - } else if (selector.getTabSelection() == ResultTab.N_K) { - csvWriter.writeHeaders(List.of("functionId", "variableId", "contingencyId", "functionReference", "value", "functionReferenceAfter")); - result.getSensitivities() - .forEach(sensitivity -> { - SensitivityWithContingency sensitivityWithContingency = (SensitivityWithContingency) sensitivity; - csvWriter.writeRow( - sensitivityWithContingency.getFuncId(), - sensitivityWithContingency.getVarId(), - sensitivityWithContingency.getContingencyId(), - sensitivityWithContingency.getFunctionReference(), - sensitivityWithContingency.getValue(), - sensitivityWithContingency.getFunctionReferenceAfter() - ); - }); + )); + } else if (selector.getTabSelection() == ResultTab.N_K) { + result.getSensitivities() + .forEach(sensitivity -> { + SensitivityWithContingency sensitivityWithContingency = (SensitivityWithContingency) sensitivity; + csvWriter.writeRow( + sensitivityWithContingency.getFuncId(), + sensitivityWithContingency.getVarId(), + sensitivityWithContingency.getContingencyId(), + sensitivityWithContingency.getFunctionReference(), + sensitivityWithContingency.getValue(), + sensitivityWithContingency.getFunctionReferenceAfter() + ); + }); + } + + csvWriter.close(); + return outputStream.toByteArray(); + } catch (IOException e) { + throw new UncheckedIOException(e); } - csvWriter.close(); - - return outputStream.toByteArray(); } } diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index bd83b66f..b9a3fb21 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -66,7 +66,6 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; @@ -346,9 +345,9 @@ public void testNoNKStillOK() { .tabSelection(ResultTab.N) .build(); - var csv = analysisService.exportSensitivityResultsAsCsv(resultUuid, exportCsvSelector); - var csvStr = new String(csv, StandardCharsets.UTF_8); - List actualLines = Arrays.asList(csvStr.split("`\n")); + byte[] csv = analysisService.exportSensitivityResultsAsCsv(resultUuid, exportCsvSelector, List.of("functionId,variableId,functionReference,value")); + String csvStr = new String(csv, StandardCharsets.UTF_8); + List actualLines = Arrays.asList(csvStr.split("\n")); List expectedLines = new ArrayList<>(List.of("functionId,variableId,functionReference,value", "l1,GEN,2.9,500.1", "l2,GEN,2.8,500.2", From 08293be896c9ed92371ec4c775fdeeecd4662f54 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Mon, 8 Jan 2024 23:26:06 +0100 Subject: [PATCH 03/18] fix headers --- .../server/SensitivityAnalysisController.java | 10 +++++----- ...tData.java => SensitivityAnalysisCsvFileInfos.java} | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/main/java/org/gridsuite/sensitivityanalysis/server/dto/{CsvFileInputData.java => SensitivityAnalysisCsvFileInfos.java} (87%) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java index 3a662095..2ec5b8ba 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java @@ -17,7 +17,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; -import org.gridsuite.sensitivityanalysis.server.dto.CsvFileInputData; +import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisCsvFileInfos; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisInputData; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisStatus; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityResultFilterOptions; @@ -211,14 +211,14 @@ public ResponseEntity getDefaultProvider() { @Operation(summary = "export sensitivity results as csv file") @ApiResponses(@ApiResponse(responseCode = "200", description = "Sensitivity results successfully exported as csv file")) public ResponseEntity exportSensitivityResultsAsCsv(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid, - @RequestBody CsvFileInputData csvFileInputData) { + @RequestBody SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos) { try { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(APPLICATION_OCTET_STREAM); - httpHeaders.setContentDispositionFormData("attachment", "sensitivity_results.csv"); + httpHeaders.setContentDispositionFormData("attachment", "sensitivity_results.zip"); byte[] csv = service.exportSensitivityResultsAsCsv(resultUuid, - getSelector(csvFileInputData.getSelector()), - csvFileInputData.getCsvHeaders()); + getSelector(sensitivityAnalysisCsvFileInfos.getSelector()), + sensitivityAnalysisCsvFileInfos.getCsvHeaders()); if (csv == null) { return ResponseEntity.notFound().build(); diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/CsvFileInputData.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java similarity index 87% rename from src/main/java/org/gridsuite/sensitivityanalysis/server/dto/CsvFileInputData.java rename to src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java index aac2bc88..d3f7ee70 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/CsvFileInputData.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java @@ -11,7 +11,7 @@ @NoArgsConstructor @Getter @Setter -public class CsvFileInputData { +public class SensitivityAnalysisCsvFileInfos { private String selector; private List csvHeaders; } From 2a8867fd9327c5226e25a1d6cc963b7bf8f55192 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 08:45:01 +0100 Subject: [PATCH 04/18] fix unit tests --- .../server/SensitivityAnalysisController.java | 6 ++-- .../dto/SensitivityAnalysisCsvFileInfos.java | 5 ++- .../service/SensitivityAnalysisService.java | 33 +++++++++++++++---- .../SensitivityAnalysisServiceTest.java | 31 ++++++++++++++--- 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java index 2ec5b8ba..55304952 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java @@ -216,9 +216,7 @@ public ResponseEntity exportSensitivityResultsAsCsv(@Parameter(descripti HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(APPLICATION_OCTET_STREAM); httpHeaders.setContentDispositionFormData("attachment", "sensitivity_results.zip"); - byte[] csv = service.exportSensitivityResultsAsCsv(resultUuid, - getSelector(sensitivityAnalysisCsvFileInfos.getSelector()), - sensitivityAnalysisCsvFileInfos.getCsvHeaders()); + byte[] csv = service.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); if (csv == null) { return ResponseEntity.notFound().build(); @@ -226,7 +224,7 @@ public ResponseEntity exportSensitivityResultsAsCsv(@Parameter(descripti return ResponseEntity.ok() .headers(httpHeaders) .body(csv); - } catch (JsonProcessingException e) { + } catch (Exception e) { return ResponseEntity.badRequest().build(); } diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java index d3f7ee70..0cb8c88c 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java @@ -1,9 +1,11 @@ package org.gridsuite.sensitivityanalysis.server.dto; +import com.powsybl.sensitivity.SensitivityFunctionType; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.SuperBuilder; +import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; import java.util.List; @@ -12,6 +14,7 @@ @Getter @Setter public class SensitivityAnalysisCsvFileInfos { - private String selector; + private SensitivityFunctionType sensitivityFunctionType; + private ResultTab tabSelection; private List csvHeaders; } diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index 1a7b3d53..e25d8d7e 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -7,9 +7,11 @@ package org.gridsuite.sensitivityanalysis.server.service; import com.fasterxml.jackson.databind.ObjectMapper; +import com.powsybl.commons.PowsyblException; import com.powsybl.sensitivity.SensitivityAnalysisProvider; import com.univocity.parsers.csv.CsvWriter; import com.univocity.parsers.csv.CsvWriterSettings; +import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisCsvFileInfos; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityWithContingency; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityFactorsIdsByGroup; @@ -21,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -158,7 +161,18 @@ public String getDefaultProvider() { return defaultProvider; } - public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, ResultsSelector selector, List headers) { + public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos) { + if (sensitivityAnalysisCsvFileInfos == null || + sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType() == null || + sensitivityAnalysisCsvFileInfos.getTabSelection() == null || + CollectionUtils.isEmpty(sensitivityAnalysisCsvFileInfos.getCsvHeaders())) { + throw new PowsyblException("Missing information to export sensitivity result: Sensitivity result tab, sensitivity function type and csv file headers must be provided"); + } + ResultsSelector selector = ResultsSelector.builder() + .functionType(sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType()) + .tabSelection(sensitivityAnalysisCsvFileInfos.getTabSelection()) + .build(); + SensitivityRunQueryResult result = getRunResult(resultUuid, selector); if (result == null) { return null; @@ -170,14 +184,14 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, ResultsSelector sel CsvWriterSettings settings = new CsvWriterSettings(); CsvWriter csvWriter = new CsvWriter(zipOutputStream, settings); - csvWriter.writeHeaders(headers); + csvWriter.writeHeaders(sensitivityAnalysisCsvFileInfos.getCsvHeaders()); if (selector.getTabSelection() == ResultTab.N) { result.getSensitivities() .forEach(sensitivity -> csvWriter.writeRow( sensitivity.getFuncId(), sensitivity.getVarId(), - sensitivity.getFunctionReference(), - sensitivity.getValue() + nullIfNan(sensitivity.getFunctionReference()), + nullIfNan(sensitivity.getValue()) )); } else if (selector.getTabSelection() == ResultTab.N_K) { result.getSensitivities() @@ -187,9 +201,10 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, ResultsSelector sel sensitivityWithContingency.getFuncId(), sensitivityWithContingency.getVarId(), sensitivityWithContingency.getContingencyId(), - sensitivityWithContingency.getFunctionReference(), - sensitivityWithContingency.getValue(), - sensitivityWithContingency.getFunctionReferenceAfter() + nullIfNan(sensitivityWithContingency.getFunctionReference()), + nullIfNan(sensitivityWithContingency.getValue()), + nullIfNan(sensitivityWithContingency.getFunctionReferenceAfter()), + nullIfNan(sensitivityWithContingency.getValueAfter()) ); }); } @@ -200,4 +215,8 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, ResultsSelector sel throw new UncheckedIOException(e); } } + + private static Double nullIfNan(double d) { + return Double.isNaN(d) ? null : d; + } } diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index b9a3fb21..76470d41 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -4,6 +4,8 @@ */ package org.gridsuite.sensitivityanalysis.server.service; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -17,8 +19,10 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.Stream; +import java.util.zip.ZipInputStream; import lombok.SneakyThrows; +import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisCsvFileInfos; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultsSelector; import org.gridsuite.sensitivityanalysis.server.SensitivityAnalysisApplication; @@ -278,7 +282,7 @@ private void testBasic(boolean specific, SensitivityAnalysisRunContext context) } @Test - public void testNoNKStillOK() { + public void testNoNKStillOK() throws Exception { List aleaIds = List.of("a1", "a2", "a3"); final List contingenciesStatuses = aleaIds.stream() .map(aleaId -> new SensitivityAnalysisResult.SensitivityContingencyStatus(aleaId, SensitivityAnalysisResult.Status.SUCCESS)) @@ -340,23 +344,40 @@ public void testNoNKStillOK() { assertThat(sensitivities, not(nullValue())); assertThat(sensitivities.size(), is(0)); - ResultsSelector exportCsvSelector = ResultsSelector.builder() - .functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) + SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos = SensitivityAnalysisCsvFileInfos.builder() + .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) .tabSelection(ResultTab.N) + .csvHeaders(List.of("functionId,variableId,functionReference,value")) .build(); - byte[] csv = analysisService.exportSensitivityResultsAsCsv(resultUuid, exportCsvSelector, List.of("functionId,variableId,functionReference,value")); + byte[] zip = analysisService.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); + byte[] csv = unzip(zip); String csvStr = new String(csv, StandardCharsets.UTF_8); List actualLines = Arrays.asList(csvStr.split("\n")); - List expectedLines = new ArrayList<>(List.of("functionId,variableId,functionReference,value", + List expectedLines = new ArrayList<>(List.of("\"functionId,variableId,functionReference,value\"", "l1,GEN,2.9,500.1", "l2,GEN,2.8,500.2", "l3,LOAD,2.1,500.9")); + actualLines.sort(String::compareTo); expectedLines.sort(String::compareTo); assertEquals(expectedLines, actualLines); } + private static byte[] unzip(byte[] zippedBytes) throws Exception { + var zipInputStream = new ZipInputStream(new ByteArrayInputStream(zippedBytes)); + var buff = new byte[1024]; + if (zipInputStream.getNextEntry() != null) { + var outputStream = new ByteArrayOutputStream(); + int l; + while ((l = zipInputStream.read(buff)) > 0) { + outputStream.write(buff, 0, l); + } + return outputStream.toByteArray(); + } + return new byte[0]; + } + @Test public void testNoNStillOK() { testNoN(false); From 8adf7c52584fc14eddaf6bc9df812367f5ceba2d Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 13:41:55 +0100 Subject: [PATCH 05/18] fix unit tests --- .../server/service/SensitivityAnalysisService.java | 7 ++++--- .../server/service/SensitivityAnalysisServiceTest.java | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index e25d8d7e..2f0028ce 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -166,7 +166,7 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysis sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType() == null || sensitivityAnalysisCsvFileInfos.getTabSelection() == null || CollectionUtils.isEmpty(sensitivityAnalysisCsvFileInfos.getCsvHeaders())) { - throw new PowsyblException("Missing information to export sensitivity result: Sensitivity result tab, sensitivity function type and csv file headers must be provided"); + throw new PowsyblException("Missing information to export sensitivity result as csv : Sensitivity result tab, sensitivity function type and csv file headers must be provided"); } ResultsSelector selector = ResultsSelector.builder() .functionType(sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType()) @@ -195,8 +195,9 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysis )); } else if (selector.getTabSelection() == ResultTab.N_K) { result.getSensitivities() - .forEach(sensitivity -> { - SensitivityWithContingency sensitivityWithContingency = (SensitivityWithContingency) sensitivity; + .stream() + .map(sensitivity -> (SensitivityWithContingency) sensitivity) + .forEach(sensitivityWithContingency -> { csvWriter.writeRow( sensitivityWithContingency.getFuncId(), sensitivityWithContingency.getVarId(), diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index 76470d41..4a05f99c 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -347,14 +347,14 @@ public void testNoNKStillOK() throws Exception { SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos = SensitivityAnalysisCsvFileInfos.builder() .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) .tabSelection(ResultTab.N) - .csvHeaders(List.of("functionId,variableId,functionReference,value")) + .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) .build(); byte[] zip = analysisService.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); byte[] csv = unzip(zip); String csvStr = new String(csv, StandardCharsets.UTF_8); List actualLines = Arrays.asList(csvStr.split("\n")); - List expectedLines = new ArrayList<>(List.of("\"functionId,variableId,functionReference,value\"", + List expectedLines = new ArrayList<>(List.of("functionId,variableId,functionReference,value", "l1,GEN,2.9,500.1", "l2,GEN,2.8,500.2", "l3,LOAD,2.1,500.9")); From dca2e841d56c4176b91befa3a1655169f883489d Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 14:17:47 +0100 Subject: [PATCH 06/18] fix unit tests --- .../SensitivityAnalysisControllerTest.java | 27 +++++++++++++++++++ .../SensitivityAnalysisServiceTest.java | 15 +---------- .../server/util/TestUtils.java | 18 +++++++++++++ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java index 1c017cc0..325548de 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java @@ -73,6 +73,8 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; @@ -84,6 +86,7 @@ import static org.gridsuite.sensitivityanalysis.server.service.NotificationService.CANCEL_MESSAGE; import static org.gridsuite.sensitivityanalysis.server.service.NotificationService.FAIL_MESSAGE; import static org.gridsuite.sensitivityanalysis.server.service.NotificationService.HEADER_USER_ID; +import static org.gridsuite.sensitivityanalysis.server.util.TestUtils.unzip; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -624,6 +627,30 @@ public void runAndSaveTest() throws Exception { assertEquals(6, (long) resNK.getTotalSensitivitiesCount()); assertEquals(2, resNK.getSensitivities().size()); + // export results as csv + SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos = SensitivityAnalysisCsvFileInfos.builder() + .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) + .tabSelection(ResultTab.N) + .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) + .build(); + result = mockMvc.perform(post("/" + VERSION + "/results/{resultUuid}/csv", RESULT_UUID) + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(sensitivityAnalysisCsvFileInfos))) + .andExpect(status().isOk()) + .andReturn(); + + byte[] zipFile = result.getResponse().getContentAsByteArray(); + byte[] csvFile = unzip(zipFile); + String csvFileAsString = new String(csvFile, StandardCharsets.UTF_8); + List actualCsvLines = Arrays.asList(csvFileAsString.split("\n")); + List expectedCsvLines = new ArrayList<>(List.of("functionId,variableId,functionReference,value", + "l1,GEN,2.9,500.1", + "l2,GEN,2.8,500.2")); + + actualCsvLines.sort(String::compareTo); + expectedCsvLines.sort(String::compareTo); + assertEquals(expectedCsvLines, actualCsvLines); + ResultsSelector filterOptionsSelector = ResultsSelector.builder().tabSelection(ResultTab.N_K) .functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1).build(); result = mockMvc.perform(get("/" + VERSION + "/results/{resultUuid}/filter-options?selector={selector}", RESULT_UUID, diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index 4a05f99c..2a6b367c 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -65,6 +65,7 @@ import com.powsybl.sensitivity.SensitivityValue; import com.powsybl.sensitivity.SensitivityVariableType; import static org.gridsuite.sensitivityanalysis.server.util.OrderMatcher.isOrderedAccordingTo; +import static org.gridsuite.sensitivityanalysis.server.util.TestUtils.unzip; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; @@ -364,20 +365,6 @@ public void testNoNKStillOK() throws Exception { assertEquals(expectedLines, actualLines); } - private static byte[] unzip(byte[] zippedBytes) throws Exception { - var zipInputStream = new ZipInputStream(new ByteArrayInputStream(zippedBytes)); - var buff = new byte[1024]; - if (zipInputStream.getNextEntry() != null) { - var outputStream = new ByteArrayOutputStream(); - int l; - while ((l = zipInputStream.read(buff)) > 0) { - outputStream.write(buff, 0, l); - } - return outputStream.toByteArray(); - } - return new byte[0]; - } - @Test public void testNoNStillOK() { testNoN(false); diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java index 1b7e748a..ad0a1b0e 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java @@ -7,6 +7,10 @@ package org.gridsuite.sensitivityanalysis.server.util; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.zip.ZipInputStream; + import static com.vladmihalcea.sql.SQLStatementCountValidator.*; /** @@ -22,4 +26,18 @@ public static void assertRequestsCount(long select, long insert, long update, lo assertUpdateCount(update); assertDeleteCount(delete); } + + public static byte[] unzip(byte[] zippedBytes) throws Exception { + var zipInputStream = new ZipInputStream(new ByteArrayInputStream(zippedBytes)); + var buff = new byte[1024]; + if (zipInputStream.getNextEntry() != null) { + var outputStream = new ByteArrayOutputStream(); + int l; + while ((l = zipInputStream.read(buff)) > 0) { + outputStream.write(buff, 0, l); + } + return outputStream.toByteArray(); + } + return new byte[0]; + } } From 5d49fa3a8759093a38920fdbe4490eac592c340f Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 14:42:34 +0100 Subject: [PATCH 07/18] fix checkstyle --- .../server/service/SensitivityAnalysisServiceTest.java | 3 --- .../gridsuite/sensitivityanalysis/server/util/TestUtils.java | 1 - 2 files changed, 4 deletions(-) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index 2a6b367c..b2348e57 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -4,8 +4,6 @@ */ package org.gridsuite.sensitivityanalysis.server.service; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -19,7 +17,6 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.zip.ZipInputStream; import lombok.SneakyThrows; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisCsvFileInfos; diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java index ad0a1b0e..b449288e 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/util/TestUtils.java @@ -6,7 +6,6 @@ */ package org.gridsuite.sensitivityanalysis.server.util; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.zip.ZipInputStream; From c852c78b7d186696c128e3bf31715164cd754096 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 15:34:01 +0100 Subject: [PATCH 08/18] add unit tests --- .../SensitivityAnalysisControllerTest.java | 8 ++++++++ .../SensitivityAnalysisServiceTest.java | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java index 325548de..cc8d85af 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java @@ -633,6 +633,13 @@ public void runAndSaveTest() throws Exception { .tabSelection(ResultTab.N) .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) .build(); + + UUID randomUuid = UUID.randomUUID(); + mockMvc.perform(post("/" + VERSION + "/results/{resultUuid}/csv", randomUuid) + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(sensitivityAnalysisCsvFileInfos))) + .andExpect(status().isNotFound()); + result = mockMvc.perform(post("/" + VERSION + "/results/{resultUuid}/csv", RESULT_UUID) .contentType(MediaType.APPLICATION_JSON) .content(mapper.writeValueAsString(sensitivityAnalysisCsvFileInfos))) @@ -651,6 +658,7 @@ public void runAndSaveTest() throws Exception { expectedCsvLines.sort(String::compareTo); assertEquals(expectedCsvLines, actualCsvLines); + // test filter options ResultsSelector filterOptionsSelector = ResultsSelector.builder().tabSelection(ResultTab.N_K) .functionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1).build(); result = mockMvc.perform(get("/" + VERSION + "/results/{resultUuid}/filter-options?selector={selector}", RESULT_UUID, diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index b2348e57..ab012078 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -69,6 +69,8 @@ import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; @@ -342,12 +344,14 @@ public void testNoNKStillOK() throws Exception { assertThat(sensitivities, not(nullValue())); assertThat(sensitivities.size(), is(0)); + // test export result as zipped csv SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos = SensitivityAnalysisCsvFileInfos.builder() .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) .tabSelection(ResultTab.N) .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) .build(); + assertNull(analysisService.exportSensitivityResultsAsCsv(UUID.randomUUID(), sensitivityAnalysisCsvFileInfos)); byte[] zip = analysisService.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); byte[] csv = unzip(zip); String csvStr = new String(csv, StandardCharsets.UTF_8); @@ -360,6 +364,22 @@ public void testNoNKStillOK() throws Exception { actualLines.sort(String::compareTo); expectedLines.sort(String::compareTo); assertEquals(expectedLines, actualLines); + + SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos2 = SensitivityAnalysisCsvFileInfos.builder() + .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) + .tabSelection(ResultTab.N_K) + .csvHeaders(List.of("functionId", "variableId", "contingencyId", "functionReference", "value", "functionReferenceAfter", "valueAfter")) + .build(); + + byte[] zip2 = analysisService.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos2); + byte[] csv2 = unzip(zip2); + String csvStr2 = new String(csv2, StandardCharsets.UTF_8); + List actualLines2 = Arrays.asList(csvStr2.split("\n")); + List expectedLines2 = new ArrayList<>(List.of("functionId,variableId,contingencyId,functionReference,value,functionReferenceAfter,valueAfter")); + + actualLines2.sort(String::compareTo); + expectedLines2.sort(String::compareTo); + assertEquals(expectedLines2, actualLines2); } @Test From 24e89dff7a33e455ea42dc42fe3c6852f3d8ec60 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 15:37:32 +0100 Subject: [PATCH 09/18] fix --- .../server/service/SensitivityAnalysisServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index ab012078..4d028331 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -69,7 +69,6 @@ import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; From 1bfbf6be25bfd8eb759b29b228636d9c7f86ed06 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 15:40:17 +0100 Subject: [PATCH 10/18] add unit test --- .../server/SensitivityAnalysisControllerTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java index cc8d85af..23165e22 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java @@ -640,6 +640,11 @@ public void runAndSaveTest() throws Exception { .content(mapper.writeValueAsString(sensitivityAnalysisCsvFileInfos))) .andExpect(status().isNotFound()); + mockMvc.perform(post("/" + VERSION + "/results/{resultUuid}/csv", RESULT_UUID) + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(SensitivityAnalysisCsvFileInfos.builder().build()))) + .andExpect(status().isBadRequest()); + result = mockMvc.perform(post("/" + VERSION + "/results/{resultUuid}/csv", RESULT_UUID) .contentType(MediaType.APPLICATION_JSON) .content(mapper.writeValueAsString(sensitivityAnalysisCsvFileInfos))) From 88660ba3d5cf5814808eacc1c70b2dc1b11ed06f Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 11 Jan 2024 15:59:02 +0100 Subject: [PATCH 11/18] fixes --- .../service/SensitivityAnalysisService.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index 2f0028ce..91cc6c16 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -196,18 +196,16 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysis } else if (selector.getTabSelection() == ResultTab.N_K) { result.getSensitivities() .stream() - .map(sensitivity -> (SensitivityWithContingency) sensitivity) - .forEach(sensitivityWithContingency -> { - csvWriter.writeRow( - sensitivityWithContingency.getFuncId(), - sensitivityWithContingency.getVarId(), - sensitivityWithContingency.getContingencyId(), - nullIfNan(sensitivityWithContingency.getFunctionReference()), - nullIfNan(sensitivityWithContingency.getValue()), - nullIfNan(sensitivityWithContingency.getFunctionReferenceAfter()), - nullIfNan(sensitivityWithContingency.getValueAfter()) - ); - }); + .map(SensitivityWithContingency.class::cast) + .forEach(sensitivityWithContingency -> csvWriter.writeRow( + sensitivityWithContingency.getFuncId(), + sensitivityWithContingency.getVarId(), + sensitivityWithContingency.getContingencyId(), + nullIfNan(sensitivityWithContingency.getFunctionReference()), + nullIfNan(sensitivityWithContingency.getValue()), + nullIfNan(sensitivityWithContingency.getFunctionReferenceAfter()), + nullIfNan(sensitivityWithContingency.getValueAfter()) + )); } csvWriter.close(); From 4694f083da10e0c99ef621af4620b29a09bc18ec Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Mon, 22 Jan 2024 13:31:14 +0100 Subject: [PATCH 12/18] add license --- .../server/dto/SensitivityAnalysisCsvFileInfos.java | 13 ++++++++++++- .../server/service/SensitivityAnalysisService.java | 4 ++-- .../server/SensitivityAnalysisControllerTest.java | 2 +- .../service/SensitivityAnalysisServiceTest.java | 4 ++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java index 0cb8c88c..255235c3 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/dto/SensitivityAnalysisCsvFileInfos.java @@ -1,3 +1,10 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + package org.gridsuite.sensitivityanalysis.server.dto; import com.powsybl.sensitivity.SensitivityFunctionType; @@ -9,12 +16,16 @@ import java.util.List; +/** + * @author Seddik Yengui + */ + @SuperBuilder @NoArgsConstructor @Getter @Setter public class SensitivityAnalysisCsvFileInfos { private SensitivityFunctionType sensitivityFunctionType; - private ResultTab tabSelection; + private ResultTab resultTab; private List csvHeaders; } diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index b6cc9792..0b67799f 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -162,13 +162,13 @@ public String getDefaultProvider() { public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos) { if (sensitivityAnalysisCsvFileInfos == null || sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType() == null || - sensitivityAnalysisCsvFileInfos.getTabSelection() == null || + sensitivityAnalysisCsvFileInfos.getResultTab() == null || CollectionUtils.isEmpty(sensitivityAnalysisCsvFileInfos.getCsvHeaders())) { throw new PowsyblException("Missing information to export sensitivity result as csv : Sensitivity result tab, sensitivity function type and csv file headers must be provided"); } ResultsSelector selector = ResultsSelector.builder() .functionType(sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType()) - .tabSelection(sensitivityAnalysisCsvFileInfos.getTabSelection()) + .tabSelection(sensitivityAnalysisCsvFileInfos.getResultTab()) .build(); SensitivityRunQueryResult result = getRunResult(resultUuid, selector); diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java index 23165e22..623b9fea 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisControllerTest.java @@ -630,7 +630,7 @@ public void runAndSaveTest() throws Exception { // export results as csv SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos = SensitivityAnalysisCsvFileInfos.builder() .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) - .tabSelection(ResultTab.N) + .resultTab(ResultTab.N) .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) .build(); diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index 4d028331..25f31d3f 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -346,7 +346,7 @@ public void testNoNKStillOK() throws Exception { // test export result as zipped csv SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos = SensitivityAnalysisCsvFileInfos.builder() .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) - .tabSelection(ResultTab.N) + .resultTab(ResultTab.N) .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) .build(); @@ -366,7 +366,7 @@ public void testNoNKStillOK() throws Exception { SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos2 = SensitivityAnalysisCsvFileInfos.builder() .sensitivityFunctionType(SensitivityFunctionType.BRANCH_ACTIVE_POWER_1) - .tabSelection(ResultTab.N_K) + .resultTab(ResultTab.N_K) .csvHeaders(List.of("functionId", "variableId", "contingencyId", "functionReference", "value", "functionReferenceAfter", "valueAfter")) .build(); From ad2310c3bdec4d382b0496e52e8360041f2f5544 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 25 Jan 2024 15:16:35 +0100 Subject: [PATCH 13/18] review fix --- .../RestResponseEntityExceptionHandler.java | 29 ++++++++++++++ .../server/SensibilityAnalysisException.java | 38 +++++++++++++++++++ .../server/SensitivityAnalysisController.java | 22 ++++------- .../service/SensitivityAnalysisService.java | 13 ++++--- 4 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java create mode 100644 src/main/java/org/gridsuite/sensitivityanalysis/server/SensibilityAnalysisException.java diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java new file mode 100644 index 00000000..3039a2cc --- /dev/null +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.gridsuite.sensitivityanalysis.server; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * @author Seddik Yengui + */ + +@ControllerAdvice +public class RestResponseEntityExceptionHandler { + @ExceptionHandler(SensibilityAnalysisException.class) + protected ResponseEntity handleSensibilityAnalysisException(SensibilityAnalysisException exception) { + return switch (exception.getType()) { + case RESULT_NOT_FOUND -> ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getMessage()); + case FILE_EXPORT_ERROR, INVALID_EXPORT_PARAMS -> ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.getMessage()); + default -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + }; + } +} diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensibilityAnalysisException.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensibilityAnalysisException.java new file mode 100644 index 00000000..9b665441 --- /dev/null +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensibilityAnalysisException.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.gridsuite.sensitivityanalysis.server; + +import java.util.Objects; + +/** + * @author Seddik Yengui + */ + +public class SensibilityAnalysisException extends RuntimeException { + public enum Type { + RESULT_NOT_FOUND, + INVALID_EXPORT_PARAMS, + FILE_EXPORT_ERROR, + } + + private final Type type; + + public SensibilityAnalysisException(Type type) { + super(Objects.requireNonNull(type.name())); + this.type = type; + } + + public SensibilityAnalysisException(Type type, String message) { + super(message); + this.type = type; + } + + public Type getType() { + return type; + } +} diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java index 10660bb4..28d60ec7 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/SensitivityAnalysisController.java @@ -220,21 +220,13 @@ public ResponseEntity getDefaultProvider() { @ApiResponses(@ApiResponse(responseCode = "200", description = "Sensitivity results successfully exported as csv file")) public ResponseEntity exportSensitivityResultsAsCsv(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid, @RequestBody SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos) { - try { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.setContentType(APPLICATION_OCTET_STREAM); - httpHeaders.setContentDispositionFormData("attachment", "sensitivity_results.zip"); - byte[] csv = service.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); - - if (csv == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok() - .headers(httpHeaders) - .body(csv); - } catch (Exception e) { - return ResponseEntity.badRequest().build(); - } + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(APPLICATION_OCTET_STREAM); + httpHeaders.setContentDispositionFormData("attachment", "sensitivity_results.zip"); + byte[] csv = service.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); + return ResponseEntity.ok() + .headers(httpHeaders) + .body(csv); } @PostMapping(value = "/networks/{networkUuid}/non-evacuated-energy/run-and-save", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java index 0b67799f..6b8a28f6 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisService.java @@ -7,10 +7,10 @@ package org.gridsuite.sensitivityanalysis.server.service; import com.fasterxml.jackson.databind.ObjectMapper; -import com.powsybl.commons.PowsyblException; import com.powsybl.sensitivity.SensitivityAnalysisProvider; import com.univocity.parsers.csv.CsvWriter; import com.univocity.parsers.csv.CsvWriterSettings; +import org.gridsuite.sensitivityanalysis.server.SensibilityAnalysisException; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisCsvFileInfos; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityWithContingency; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; @@ -26,7 +26,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.UncheckedIOException; import java.util.List; import java.util.Map; import java.util.Objects; @@ -35,6 +34,10 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import static org.gridsuite.sensitivityanalysis.server.SensibilityAnalysisException.Type.FILE_EXPORT_ERROR; +import static org.gridsuite.sensitivityanalysis.server.SensibilityAnalysisException.Type.INVALID_EXPORT_PARAMS; +import static org.gridsuite.sensitivityanalysis.server.SensibilityAnalysisException.Type.RESULT_NOT_FOUND; + /** * @author Franck Lecuyer */ @@ -164,7 +167,7 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysis sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType() == null || sensitivityAnalysisCsvFileInfos.getResultTab() == null || CollectionUtils.isEmpty(sensitivityAnalysisCsvFileInfos.getCsvHeaders())) { - throw new PowsyblException("Missing information to export sensitivity result as csv : Sensitivity result tab, sensitivity function type and csv file headers must be provided"); + throw new SensibilityAnalysisException(INVALID_EXPORT_PARAMS, "Missing information to export sensitivity result as csv : Sensitivity result tab, sensitivity function type and csv file headers must be provided"); } ResultsSelector selector = ResultsSelector.builder() .functionType(sensitivityAnalysisCsvFileInfos.getSensitivityFunctionType()) @@ -173,7 +176,7 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysis SensitivityRunQueryResult result = getRunResult(resultUuid, selector); if (result == null) { - return null; + throw new SensibilityAnalysisException(RESULT_NOT_FOUND, "The sensitivity analysis result '" + resultUuid + "' does not exist"); } try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -209,7 +212,7 @@ public byte[] exportSensitivityResultsAsCsv(UUID resultUuid, SensitivityAnalysis csvWriter.close(); return outputStream.toByteArray(); } catch (IOException e) { - throw new UncheckedIOException(e); + throw new SensibilityAnalysisException(FILE_EXPORT_ERROR, e.getMessage()); } } From 5c2fd87dd95c4a64285c8efc1889df9936f7ded6 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 25 Jan 2024 15:44:21 +0100 Subject: [PATCH 14/18] fix unit tests --- .../server/service/SensitivityAnalysisServiceTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index 25f31d3f..207ac62b 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -19,6 +19,7 @@ import java.util.stream.Stream; import lombok.SneakyThrows; +import org.gridsuite.sensitivityanalysis.server.SensibilityAnalysisException; import org.gridsuite.sensitivityanalysis.server.dto.SensitivityAnalysisCsvFileInfos; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultTab; import org.gridsuite.sensitivityanalysis.server.dto.resultselector.ResultsSelector; @@ -70,6 +71,7 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; @@ -350,7 +352,8 @@ public void testNoNKStillOK() throws Exception { .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) .build(); - assertNull(analysisService.exportSensitivityResultsAsCsv(UUID.randomUUID(), sensitivityAnalysisCsvFileInfos)); + assertThrows(SensibilityAnalysisException.class, () -> analysisService.exportSensitivityResultsAsCsv(UUID.randomUUID(), sensitivityAnalysisCsvFileInfos)); + byte[] zip = analysisService.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); byte[] csv = unzip(zip); String csvStr = new String(csv, StandardCharsets.UTF_8); From 95f9f86368b58962b6a1ea3531de1bd5915fed99 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 25 Jan 2024 15:58:42 +0100 Subject: [PATCH 15/18] fix checkstyle --- .../server/service/SensitivityAnalysisServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index 207ac62b..f7d14ec6 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -70,7 +70,6 @@ import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; From e554bd94eb65ac59357dce17de6397b78b7ab9ed Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 25 Jan 2024 18:03:29 +0100 Subject: [PATCH 16/18] fix checkstyle --- .../server/RestResponseEntityExceptionHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java index 3039a2cc..e3631f6a 100644 --- a/src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java +++ b/src/main/java/org/gridsuite/sensitivityanalysis/server/RestResponseEntityExceptionHandler.java @@ -22,7 +22,8 @@ public class RestResponseEntityExceptionHandler { protected ResponseEntity handleSensibilityAnalysisException(SensibilityAnalysisException exception) { return switch (exception.getType()) { case RESULT_NOT_FOUND -> ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getMessage()); - case FILE_EXPORT_ERROR, INVALID_EXPORT_PARAMS -> ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.getMessage()); + case FILE_EXPORT_ERROR -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exception.getMessage()); + case INVALID_EXPORT_PARAMS -> ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.getMessage()); default -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); }; } From d6f8b26c05b7b995866924d66f39583a5c626eb0 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 25 Jan 2024 18:38:43 +0100 Subject: [PATCH 17/18] add unit tests --- .../SensitivityAnalysisServiceTest.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index f7d14ec6..856807aa 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -384,12 +384,12 @@ public void testNoNKStillOK() throws Exception { } @Test - public void testNoNStillOK() { + public void testNoNStillOK() throws Exception { testNoN(false); testNoN(true); } - private void testNoN(boolean specific) { + private void testNoN(boolean specific) throws Exception { List aleaIds = List.of("a1", "a2", "a3"); final List contingenciesStatuses = aleaIds.stream() .map(aleaId -> new SensitivityAnalysisResult.SensitivityContingencyStatus(aleaId, SensitivityAnalysisResult.Status.SUCCESS)) @@ -454,6 +454,28 @@ private void testNoN(boolean specific) { sensitivityVals = sensitivities.stream().map(SensitivityOfTo::getValue).collect(Collectors.toList()); assertThat(sensitivityVals, not(hasItem(500.2))); assertThat(sensitivityVals, isOrderedAccordingTo(Comparator.naturalOrder())); + + SensitivityAnalysisCsvFileInfos sensitivityAnalysisCsvFileInfos = SensitivityAnalysisCsvFileInfos.builder() + .sensitivityFunctionType(MW_FUNC_TYPE) + .resultTab(ResultTab.N_K) + .csvHeaders(List.of("functionId", "variableId", "contingencyId", "functionReference", "value", "functionReferenceAfter", "valueAfter")) + .build(); + + byte[] zip = analysisService.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); + byte[] csv = unzip(zip); + String csvStr = new String(csv, StandardCharsets.UTF_8); + List actualLines = Arrays.asList(csvStr.split("\n")); + List expectedLines = new ArrayList<>(List.of("functionId,variableId,contingencyId,functionReference,value,functionReferenceAfter,valueAfter", + "l1,GEN,a1,0.0,0.0,2.7,500.3", + "l1,GEN,a2,0.0,0.0,2.6,500.4", + "l1,GEN,a3,0.0,0.0,2.5,500.5", + "l3,LOAD,a1,0.0,0.0,2.3,500.7", + "l3,LOAD,a2,0.0,0.0,2.4,500.6", + "l3,LOAD,a3,0.0,0.0,2.2,500.8")); + + actualLines.sort(String::compareTo); + expectedLines.sort(String::compareTo); + assertEquals(expectedLines, actualLines); } @SneakyThrows From f8b0ad69e305ad0c69c64af332cfb8d8d6a1aef8 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Mon, 29 Jan 2024 18:05:21 +0100 Subject: [PATCH 18/18] fix code smell --- .../server/service/SensitivityAnalysisServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java index 856807aa..9892e418 100644 --- a/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java +++ b/src/test/java/org/gridsuite/sensitivityanalysis/server/service/SensitivityAnalysisServiceTest.java @@ -351,7 +351,8 @@ public void testNoNKStillOK() throws Exception { .csvHeaders(List.of("functionId", "variableId", "functionReference", "value")) .build(); - assertThrows(SensibilityAnalysisException.class, () -> analysisService.exportSensitivityResultsAsCsv(UUID.randomUUID(), sensitivityAnalysisCsvFileInfos)); + UUID randomUuid = UUID.randomUUID(); + assertThrows(SensibilityAnalysisException.class, () -> analysisService.exportSensitivityResultsAsCsv(randomUuid, sensitivityAnalysisCsvFileInfos)); byte[] zip = analysisService.exportSensitivityResultsAsCsv(resultUuid, sensitivityAnalysisCsvFileInfos); byte[] csv = unzip(zip);