diff --git a/src/main/java/com/rte_france/antares/datamanager_back/controller/UserController.java b/src/main/java/com/rte_france/antares/datamanager_back/controller/UserController.java index 3f550bf6..3227d1e7 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/controller/UserController.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/controller/UserController.java @@ -15,12 +15,10 @@ public class UserController { private final LdapClientEmployeeService ldapClientEmployeeService; - private final LdapMapper ldapMapper; - @GetMapping("/{nni}") public ResponseEntity getUserByNni(@PathVariable String nni) { - UserInfoDto user = ldapMapper.toUserDto(ldapClientEmployeeService.getUserByNni(nni)); + UserInfoDto user = LdapMapper.toUserDto(ldapClientEmployeeService.getUserByNni(nni)); if (user == null) { return ResponseEntity.notFound().build(); } @@ -29,7 +27,7 @@ public ResponseEntity getUserByNni(@PathVariable String nni) { @PostMapping("/list") public ResponseEntity> getUsersByListNni(@RequestBody List listNni) { - List users = ldapMapper.toUsersDto(ldapClientEmployeeService.getUsersByListNni(listNni)); + List users = LdapMapper.toUsersDto(ldapClientEmployeeService.getUsersByListNni(listNni)); return ResponseEntity.ok(users); } } diff --git a/src/main/java/com/rte_france/antares/datamanager_back/mapper/LdapMapper.java b/src/main/java/com/rte_france/antares/datamanager_back/mapper/LdapMapper.java index 0f0d5510..f91327fb 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/mapper/LdapMapper.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/mapper/LdapMapper.java @@ -2,14 +2,14 @@ import com.rte_france.antares.datamanager_back.configuration.gaia.Employee; import com.rte_france.antares.datamanager_back.dto.UserInfoDto; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; +import lombok.*; import java.util.Collections; import java.util.List; -@Component -@RequiredArgsConstructor +@Value +@Builder(toBuilder = true) +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class LdapMapper { public static List toUsersDto(List employees) { diff --git a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LinkFileProcessorServiceImpl.java b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LinkFileProcessorServiceImpl.java index 4d86fa76..650750ca 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LinkFileProcessorServiceImpl.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LinkFileProcessorServiceImpl.java @@ -70,9 +70,8 @@ public TrajectoryEntity processLinkFile(Path path, String horizon, Integer study ); String createdBy = userService.getCurrentUserDetails().getNni(); - List areaNames = findListArea(studyId); - List listLink = buildLinkList(path, horizon, areaNames); + List listLink = buildLinkList(path, horizon); TrajectoryEntity trajectory; if (trajectoryEntity.isPresent() && checkTrajectoryVersion(path, trajectoryEntity.get())) { @@ -86,6 +85,7 @@ public TrajectoryEntity processLinkFile(Path path, String horizon, Integer study TrajectoryEntity secondTrajectory = trajectoryRepository.findByTypeAndStudyId(TrajectoryType.AREA.name(), studyId).stream().findFirst().orElse(null); String userNni = findUserNni(); + List areaNames = findListArea(studyId); checkForWarnings(path, horizon, studyId, warningMessageEntities, userNni, trajectory); checkConsistencyTrajectoryLinkAndArea(listLink, areaNames, warningMessageEntities, studyId, trajectory.getId(), secondTrajectory, userNni); @@ -186,7 +186,7 @@ public TrajectoryEntity saveTrajectory(TrajectoryEntity trajectory, List buildLinkList(Path path, String horizon, List listArea) throws IOException { + private List buildLinkList(Path path, String horizon) { List linkEntities = new ArrayList<>(); try (InputStream inputStream = Files.newInputStream(path); Workbook workbook = WorkbookFactory.create(inputStream)) { diff --git a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LoadFileProcessorServiceImpl.java b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LoadFileProcessorServiceImpl.java index 90648693..9c6b4ae5 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LoadFileProcessorServiceImpl.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/LoadFileProcessorServiceImpl.java @@ -85,7 +85,7 @@ public Set checkForMissingLoadByAreaFromDb(String horizon, studyId, userNni, trajectory, - getFileCheckerByDatabase(horizon, trajectory, studyId) + getFileCheckerByDatabase(horizon, trajectory) ); } @@ -164,7 +164,7 @@ private LoadChecker getFileCheckerByPath(Path trajectoryPath, String horizon) { * Returns a LoadChecker that checks for file existence in the database. * If the file does not exist, it creates a new LoadEntity and saves it. */ - private LoadChecker getFileCheckerByDatabase(String horizon, TrajectoryEntity trajectory, Integer studyId) { + private LoadChecker getFileCheckerByDatabase(String horizon, TrajectoryEntity trajectory) { if (trajectory.getLoadEntities() != null && !trajectory.getLoadEntities().isEmpty()) { Set areasInThisOthers = trajectory.getLoadEntities().stream() .map(LoadEntity::getArea) diff --git a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/ThermalFileProcessorServiceImpl.java b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/ThermalFileProcessorServiceImpl.java index d944ab7d..bf0befc5 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/ThermalFileProcessorServiceImpl.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/ThermalFileProcessorServiceImpl.java @@ -47,7 +47,10 @@ public class ThermalFileProcessorServiceImpl implements ThermalFileProcessorServ private final StudyRepository studyRepository; private static final String YEAR_MONTH_PATTERN = "%04d_%02d"; + private static final String UNKNOWN_USER = "UNKNOWN__USER"; + private record ThermalRow(Row row, Row header, String horizon, boolean isCivilYear, String technology, + String rowArea) {} @Override public List buildThermalCommonParameterValuesList(Path path, String horizon) throws IOException { @@ -102,7 +105,7 @@ public List buildThermalCommonParameterValuesList( @Override public TrajectoryEntity processThermalCommonParameterFile(Path path, String horizon, List list, TrajectoryType type) throws IOException { - String createdBy = userService.getCurrentUserDetails() != null ? userService.getCurrentUserDetails().getNni() : "UNKNOWN__USER"; + String createdBy = userService.getCurrentUserDetails() != null ? userService.getCurrentUserDetails().getNni() : UNKNOWN_USER; // Find existing trajectory for same file name/horizon/type Optional existingOpt = trajectoryRepository.findFirstByFileNameAndHorizonAndTypeOrderByVersionDesc( getFileNameWithoutExtensionAndWithoutPrefix(path.getFileName().toString(), TrajectoryType.THERMAL_TECHNICAL_COMMON_PARAMETER.name()), @@ -129,7 +132,7 @@ public TrajectoryEntity processThermalCommonParameterFile(Path path, String hori * @param path the path to the file to process */ public TrajectoryEntity processThermalCapacityFile(Path path, String horizon, ThermalClusterCapacityDto thermalClusterCapacityDto, TrajectoryType type, String area, String technology) throws IOException { - String createdBy = userService.getCurrentUserDetails() != null ? userService.getCurrentUserDetails().getNni() : "UNKNOWN__USER"; + String createdBy = userService.getCurrentUserDetails() != null ? userService.getCurrentUserDetails().getNni() : UNKNOWN_USER; return saveThermalCapacitiesTrajectory(buildTrajectory(path, 0, horizon, createdBy, TrajectoryType.THERMAL_CAPACITY, area, technology), thermalClusterCapacityDto, type); } @@ -197,14 +200,16 @@ public ThermalClusterCapacityDto buildThermalClusterCapacityValuesList( if (row.getRowNum() == 0) continue; String rowArea = row.getCell(1).getStringCellValue().toUpperCase(); + var thermalRow = new ThermalRow(row, header, horizon, isCivilYear, technology, rowArea); if (!area.equals(OTHERS_AREA)) { if (rowArea.equals(area.toUpperCase())) { isSpecificAreaFound = true; - processThermalRow(row, header, horizon, isCivilYear, technology, rowArea, capacities, checksumBuilder); + + processThermalRow(thermalRow, capacities, checksumBuilder); } } else { otherAreas.add(rowArea); - processThermalRow(row, header, horizon, isCivilYear, technology, rowArea, capacities, checksumBuilder); + processThermalRow(thermalRow, capacities, checksumBuilder); } } } catch (IOException e) { @@ -280,7 +285,7 @@ public WarningMessageEntity buildWarningMessage(Path path, String area, Integer .httpStatus(HttpStatus.NOT_FOUND) .build())) .creationDate(LocalDateTime.now()) - .createdBy(userService.getCurrentUserDetails() != null ? userService.getCurrentUserDetails().getNni() : "UNKNOWN__USER") + .createdBy(userService.getCurrentUserDetails() != null ? userService.getCurrentUserDetails().getNni() : UNKNOWN_USER) .isAck(false) .build(); } else { @@ -297,27 +302,26 @@ private List getStudyAreasForCurrentStudy(Integer studyId) { .toList(); } - private void processThermalRow(Row row, Row header, String horizon, boolean isCivilYear, String technology, - String rowArea, List result, StringBuilder checksum) { - String techName = row.getCell(2).getStringCellValue(); - String clusterName = row.getCell(3).getStringCellValue(); - String categoryStr = row.getCell(4).getStringCellValue().toLowerCase(); + private void processThermalRow(ThermalRow thermalRow, List result, StringBuilder checksum) { + String techName = thermalRow.row().getCell(2).getStringCellValue(); + String clusterName = thermalRow.row().getCell(3).getStringCellValue(); + String categoryStr = thermalRow.row().getCell(4).getStringCellValue().toLowerCase(); - if (technology != null && !technology.isEmpty() && !techName.equalsIgnoreCase(technology)) return; + if (thermalRow.technology() != null && !thermalRow.technology().isEmpty() && !techName.equalsIgnoreCase(thermalRow.technology())) return; - for (int i = 5; i < header.getLastCellNum(); i++) { - String monthYear = header.getCell(i).getStringCellValue(); - if (!isCellInHorizon(monthYear, horizon, isCivilYear)) continue; + for (int i = 5; i < thermalRow.header().getLastCellNum(); i++) { + String monthYear = thermalRow.header().getCell(i).getStringCellValue(); + if (!isCellInHorizon(monthYear, thermalRow.horizon(), thermalRow.isCivilYear())) continue; ThermalCategoryEnum category = categoryStr.equals(ThermalCategoryEnum.POWER.name().toLowerCase()) ? ThermalCategoryEnum.POWER : ThermalCategoryEnum.NUMBER; - double value = capacityValue(row, i, horizon); - boolean toUse = row.getCell(0).getNumericCellValue() == 0; + double value = capacityValue(thermalRow.row(), i, thermalRow.horizon()); + boolean toUse = thermalRow.row().getCell(0).getNumericCellValue() == 0; // Ajout des valeurs au checksum - checksum.append(rowArea).append("|") + checksum.append(thermalRow.rowArea()).append("|") .append(techName).append("|") .append(clusterName).append("|") .append(category.name()).append("|") @@ -327,7 +331,7 @@ private void processThermalRow(Row row, Row header, String horizon, boolean isCi ThermalClusterCapacityEntity entity = ThermalClusterCapacityEntity.builder() .toUse(toUse) - .area(rowArea) + .area(thermalRow.rowArea()) .thermalClusterRef(findOrCreateThermalClusterRef(techName, clusterName)) .category(category) .monthYear(monthYear) @@ -476,8 +480,7 @@ public boolean isCellInHorizon(String monthYear, String horizon, boolean isCivil } else { // Année à cheval : juillet année horizon à juin année horizon+1 if (year == horizonYear && month >= 7) return true; - if (year == horizonYear + 1 && month <= 6) return true; - return false; + return year == horizonYear + 1 && month <= 6; } } @@ -613,7 +616,7 @@ private String calculateChecksum(String input) { } return hexString.toString(); } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Erreur lors du calcul du checksum", e); + throw TechnicalException.builder().message("Erreur lors du calcul du checksum: " + e.getMessage()).build(); } } } diff --git a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/TrajectoryServiceImpl.java b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/TrajectoryServiceImpl.java index 8585521f..61cb2618 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/service/impl/TrajectoryServiceImpl.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/service/impl/TrajectoryServiceImpl.java @@ -284,7 +284,7 @@ public TrajectoryEntity processTrajectory(TrajectoryType trajectoryType, String * @throws IOException if an I/O error occurs */ public TrajectoryEntity processThermalCapacityTrajectory(String trajectoryToUse, String horizon, Integer studyId, boolean isCivilYear, String area, String technology) throws IOException { - if (trajectoryToUse == null || !trajectoryToUse.toLowerCase().startsWith("thermal_")) { + if (trajectoryToUse == null || !trajectoryToUse.toLowerCase().startsWith(CAPACITY_PREFIX)) { throw BusinessException.builder() .message("The trajectory file name must start with 'thermal_'") .httpStatus(HttpStatus.BAD_REQUEST) @@ -440,9 +440,9 @@ private boolean isValidTrajectoryFile(Path path, TrajectoryType trajectoryType) @Override public List findTrajectoriesByTypeAndStudyId(String trajectoryType, Integer studyId) { - List trajectoryEntities = trajectoryRepository.findByTypeAndStudyId(trajectoryType, studyId).stream() - .peek(trajectory -> - trajectory.setWarningMessages(filterWarningMessages(studyId, trajectory.getWarningMessages()))).toList(); + List trajectoryEntities = trajectoryRepository.findByTypeAndStudyId(trajectoryType, studyId); + trajectoryEntities.forEach(trajectory -> + trajectory.setWarningMessages(filterWarningMessages(studyId, trajectory.getWarningMessages()))); return TrajectoryMapper.toTrajectoryDtos(trajectoryEntities); } @@ -717,10 +717,10 @@ public List getTrajectoryDataByTypeAndId(TrajectoryType traje @Override public Map countWarningMessage(Integer studyId) { - return trajectoryRepository.findByTypeAndStudyId(null, studyId).stream() - .peek(trajectory -> - trajectory.setWarningMessages(filterWarningMessages(studyId, trajectory.getWarningMessages()))).toList() - .stream() + var trajectories = trajectoryRepository.findByTypeAndStudyId(null, studyId); + trajectories.forEach(trajectory -> + trajectory.setWarningMessages(filterWarningMessages(studyId, trajectory.getWarningMessages()))); + return trajectories.stream() .collect(Collectors.groupingBy( TrajectoryEntity::getType, Collectors.summingInt(trajectory -> trajectory.getWarningMessages() != null ? trajectory.getWarningMessages().size() : 0) diff --git a/src/main/java/com/rte_france/antares/datamanager_back/util/Utils.java b/src/main/java/com/rte_france/antares/datamanager_back/util/Utils.java index 0ba783af..cafd850b 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/util/Utils.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/util/Utils.java @@ -23,7 +23,6 @@ import java.nio.file.Path; import java.time.Instant; import java.time.LocalDateTime; -import java.time.Year; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; @@ -192,11 +191,6 @@ else if (Objects.equals(trajectoryType, TrajectoryType.THERMAL_TECHNICAL_COMMON_ return fileName.substring(0, lastDotIndex); } - private static String isLinkTypePrefix(String trajectoryType) { - return Objects.equals(trajectoryType, TrajectoryType.LINK.toString()) ? LINKS_PREFIX : ""; - } - - public static boolean isSheetNameYearNumber(Sheet sheet) { String sheetName = sheet.getSheetName(); try { diff --git a/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/AreasValidator.java b/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/AreasValidator.java index d03da124..2dba4a78 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/AreasValidator.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/AreasValidator.java @@ -4,7 +4,6 @@ import com.rte_france.antares.datamanager_back.exception.BusinessException; import com.rte_france.antares.datamanager_back.exception.TechnicalException; import com.rte_france.antares.datamanager_back.util.excel_file_validators.columns_enum.AreaColumns; -import lombok.NoArgsConstructor; import org.apache.poi.ss.usermodel.*; import org.springframework.http.HttpStatus; @@ -39,7 +38,7 @@ public static void validateAreaColumns(Path path, String horizon) throws Busines checkColumnsRules(sheet, horizon, AreaColumns.getBooleanColumnNames(), AreaColumns.getStringColumnNames(), TrajectoryType.AREA.name()); checkAreasValuesLength(sheet, horizon, AreaColumns.AREAS.getDisplayName()); - checkForDuplicateValues(sheet, AreaColumns.AREAS.getDisplayName(), path, horizon, false, TrajectoryType.AREA.name()); + checkForDuplicateValues(sheet, AreaColumns.AREAS.getDisplayName(), horizon, false, TrajectoryType.AREA.name()); } catch (IOException e) { throw TechnicalException.builder() .message("Error reading file: {0}") diff --git a/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/ExcelCommonValidator.java b/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/ExcelCommonValidator.java index 23cbbc4a..d11c573d 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/ExcelCommonValidator.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/ExcelCommonValidator.java @@ -6,7 +6,9 @@ import com.rte_france.antares.datamanager_back.util.excel_file_validators.columns_enum.AreaColumns; import com.rte_france.antares.datamanager_back.util.excel_file_validators.columns_enum.ExcelFileType; import com.rte_france.antares.datamanager_back.util.excel_file_validators.columns_enum.LinksColumns; +import lombok.AccessLevel; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.*; import org.springframework.http.HttpStatus; @@ -22,6 +24,7 @@ @Slf4j @Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class ExcelCommonValidator { @@ -200,7 +203,6 @@ public static void checkBooleanColumns(Sheet sheet, String horizon, List ? LinksColumns.NAME.name() : null); - int identifierColumnIndex = identifierColumn != null ? findColumnIndex(sheet, identifierColumn, horizon, trajectoryType) : -1; @@ -332,7 +334,7 @@ static int findColumnIndex(Sheet sheet, String columnName, String horizon, Strin .build()); } - public static void checkForDuplicateValues(Sheet sheet, String columnName, Path path, String horizon, boolean checkSymmetric, String trajectoryType) { + public static void checkForDuplicateValues(Sheet sheet, String columnName, String horizon, boolean checkSymmetric, String trajectoryType) { int columnIndex = findColumnIndex(sheet, columnName, horizon, trajectoryType); Map seenValues = new HashMap<>(); Set identicalDuplicates = new TreeSet<>(); diff --git a/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/LinksValidator.java b/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/LinksValidator.java index 34080802..b3e6df4d 100644 --- a/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/LinksValidator.java +++ b/src/main/java/com/rte_france/antares/datamanager_back/util/excel_file_validators/LinksValidator.java @@ -34,7 +34,7 @@ public static void linksDuplicateAndCellsValuesChecks(Path path, ExcelFileType f Sheet sheet = workbook.getSheet(horizon); if (fileType == ExcelFileType.LINKS) { - checkForDuplicateValues(sheet, LinksColumns.NAME.getDisplayName(), path, horizon, true, TrajectoryType.LINK.name()); + checkForDuplicateValues(sheet, LinksColumns.NAME.getDisplayName(), horizon, true, TrajectoryType.LINK.name()); checkColumnsRules(sheet, horizon, LinksColumns.getNumericColumnNames(), LinksColumns.getBooleanColumnNames(), Collections.singletonList(LinksColumns.NAME.getDisplayName()),TrajectoryType.LINK.name()); } } catch (IOException e) { diff --git a/src/test/java/com/rte_france/antares/datamanager_back/service/LinkFileProcessorServiceImplTest.java b/src/test/java/com/rte_france/antares/datamanager_back/service/LinkFileProcessorServiceImplTest.java index ed4b7f7b..d5ef3418 100644 --- a/src/test/java/com/rte_france/antares/datamanager_back/service/LinkFileProcessorServiceImplTest.java +++ b/src/test/java/com/rte_france/antares/datamanager_back/service/LinkFileProcessorServiceImplTest.java @@ -231,13 +231,12 @@ void testProcessLinkFileAlphebaticallyOrderedException() throws IOException { .thenReturn(Optional.of(trajectory)); - var exception = assertThrows(BusinessException.class, () -> { - linkFileProcessorService.processLinkFile(tempFile, "2032-2033", 1); - }); + var exception = assertThrows(BusinessException.class, () -> + linkFileProcessorService.processLinkFile(tempFile, "2032-2033", 1)); System.out.println(exception.getMessage()); assertTrue(exception.getMessage().contains("Links {1} must be arranged in alphabetical order.")); - assertEquals(exception.getErrorMessageArguments().get(1), "FR-CH, GE-FR"); + assertEquals("FR-CH, GE-FR", exception.getErrorMessageArguments().get(1)); } @Test @@ -253,9 +252,8 @@ void validateLinkAreas_validLink() { void validateLinkAreas_invalidLinkFormat() { List areaNames = List.of("FR", "CH", "IT"); String link = "FRCH"; - BusinessException exception = assertThrows(BusinessException.class, () -> { - linkFileProcessorService.validateLinkAreas(link, areaNames); - }); + BusinessException exception = assertThrows(BusinessException.class, () -> + linkFileProcessorService.validateLinkAreas(link, areaNames)); assertEquals("Error: Link {0} in LINKS file is not valid", exception.getMessage()); assertEquals(Collections.singletonList("FRCH"), exception.getErrorMessageArguments()); } @@ -264,9 +262,8 @@ void validateLinkAreas_invalidLinkFormat() { void validateLinkAreas_areaNotInTrajectory() { List areaNames = List.of("FR", "CH", "IT", "ZE", "OT"); String link = "FR-ES"; - BusinessException exception = assertThrows(BusinessException.class, () -> { - linkFileProcessorService.validateLinkAreas(link, areaNames); - }); + BusinessException exception = assertThrows(BusinessException.class, () -> + linkFileProcessorService.validateLinkAreas(link, areaNames)); assertEquals("Areas {0} in LINKS file is not present in AREA trajectory", exception.getMessage()); assertEquals(List.of("ES"), exception.getErrorMessageArguments()); @@ -535,9 +532,8 @@ void throwBusinessExceptionWhenHorizonNotFoundInHeaderRow() { when(mockSheet.getRow(0)).thenReturn(mockRow); when(mockRow.iterator()).thenReturn(Collections.emptyIterator()); - BusinessException exception = assertThrows(BusinessException.class, () -> { - linkFileProcessorService.findCellIndexByHorizon(mockSheet, "2030-2031"); - }); + BusinessException exception = assertThrows(BusinessException.class, () -> + linkFileProcessorService.findCellIndexByHorizon(mockSheet, "2030-2031")); assertEquals("Horizon {0} not found in the header row.", exception.getMessage()); assertEquals(Collections.singletonList("2030-2031"), exception.getErrorMessageArguments()); @@ -548,9 +544,8 @@ void throwBusinessExceptionWhenHeaderRowIsMissing() { Sheet mockSheet = mock(Sheet.class); when(mockSheet.getRow(0)).thenReturn(null); - TechnicalException exception = assertThrows(TechnicalException.class, () -> { - linkFileProcessorService.findCellIndexByHorizon(mockSheet, "2030-2031"); - }); + TechnicalException exception = assertThrows(TechnicalException.class, () -> + linkFileProcessorService.findCellIndexByHorizon(mockSheet, "2030-2031")); assertEquals("Header row is missing in the sheet.", exception.getMessage()); } diff --git a/src/test/java/com/rte_france/antares/datamanager_back/service/ThermalFileProcessorServiceImplTest.java b/src/test/java/com/rte_france/antares/datamanager_back/service/ThermalFileProcessorServiceImplTest.java index de8744f1..dd839f24 100644 --- a/src/test/java/com/rte_france/antares/datamanager_back/service/ThermalFileProcessorServiceImplTest.java +++ b/src/test/java/com/rte_france/antares/datamanager_back/service/ThermalFileProcessorServiceImplTest.java @@ -23,6 +23,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Optional; import java.util.Set; @@ -304,7 +306,244 @@ void buildThermalClusterCapacityValuesList_shouldThrowTechnicalExceptionWhenIOEx assertThrows(TechnicalException.class, () -> thermalFileProcessorService.buildThermalClusterCapacityValuesList(mockPath, horizon, true, area, technology,1)); } + + } + @Test + void buildThermalClusterCapacityValuesList_shouldThrowTechnicalExceptionWhenNoSuchAlgorithmExceptionOccurs(@TempDir Path tempDir) throws Exception { + var file = mockExcelFile(tempDir, "test.xlsx", () -> { + try (var out = new ByteArrayOutputStream(); var wb = new XSSFWorkbook()) { + var sheet = wb.createSheet("Sheet1"); + var header = sheet.createRow(0); + header.createCell(0).setCellValue("ToUse"); + header.createCell(1).setCellValue("Area"); + header.createCell(2).setCellValue("Type"); + header.createCell(3).setCellValue("Cluster"); + header.createCell(4).setCellValue("Category"); + for (var i = 1; i <= 12; i++) { + header.createCell(4 + i).setCellValue(String.format("%04d_%02d", 2025, i)); + } + var row = sheet.createRow(1); + row.createCell(0).setCellValue(0.0); + row.createCell(1).setCellValue("FR"); + row.createCell(2).setCellValue("CCGT"); + row.createCell(3).setCellValue("Cluster1"); + row.createCell(4).setCellValue("power"); + for (var i = 1; i <= 12; i++) { + row.createCell(4 + i).setCellValue(100.0); + } + wb.write(out); + return out.toByteArray(); + } + }); + when(areaRepository.findAllByStudyId(any())).thenReturn(List.of(AreaEntity.builder().id(1).name("FR").build())); + when(thermalClusterRefRepository.findAll()).thenReturn(List.of()); + var tech = ThermalTechnology.builder().name("CCGT").build(); + when(thermalTechnologyRepository.findThermalTechnologyByName("CCGT")).thenReturn(Optional.of(tech)); + when(thermalClusterRefRepository.save(any())).thenAnswer(inv -> { + ThermalClusterRef ref = inv.getArgument(0); + ref.setId(1); + return ref; + }); + + try (var mdMock = mockStatic(MessageDigest.class)) { + mdMock.when(() -> MessageDigest.getInstance("SHA-256")) + .thenThrow(new NoSuchAlgorithmException("SHA-256 not available")); + + var ex = assertThrows(TechnicalException.class, () -> + thermalFileProcessorService.buildThermalClusterCapacityValuesList(file, "2025", true, "FR", "CCGT", 1) + ); + assertTrue(ex.getMessage().contains("Erreur lors du calcul du checksum")); + } + } + + @Test + void buildThermalClusterCapacityValuesList_shouldThrowBusinessExceptionWhenCellIsNull(@TempDir Path tempDir) throws Exception { + var file = mockExcelFile(tempDir, "test.xlsx", () -> { + try (var out = new ByteArrayOutputStream(); var wb = new XSSFWorkbook()) { + var sheet = wb.createSheet("Sheet1"); + var header = sheet.createRow(0); + header.createCell(0).setCellValue("ToUse"); + header.createCell(1).setCellValue("Area"); + header.createCell(2).setCellValue("Type"); + header.createCell(3).setCellValue("Cluster"); + header.createCell(4).setCellValue("Category"); + header.createCell(5).setCellValue("2025_01"); + + var row = sheet.createRow(1); + row.createCell(0).setCellValue(0.0); + row.createCell(1).setCellValue("FR"); + row.createCell(2).setCellValue("CCGT"); + row.createCell(3).setCellValue("Cluster1"); + row.createCell(4).setCellValue("power"); + // cell 5 is missing for the test + wb.write(out); + return out.toByteArray(); + } + }); + when(areaRepository.findAllByStudyId(any())).thenReturn(List.of(AreaEntity.builder().id(1).name("FR").build())); + assertThrows(BusinessException.class, () -> + thermalFileProcessorService.buildThermalClusterCapacityValuesList(file, "2025", true, "FR", "CCGT", 1) + ); + } + + @Test + void buildThermalClusterCapacityValuesList_shouldThrowBusinessExceptionWhenCellIsNonNumericString(@TempDir Path tempDir) throws Exception { + var file = mockExcelFile(tempDir, "test.xlsx", () -> { + try (var out = new ByteArrayOutputStream(); var wb = new XSSFWorkbook()) { + var sheet = wb.createSheet("Sheet1"); + var header = sheet.createRow(0); + header.createCell(0).setCellValue("ToUse"); + header.createCell(1).setCellValue("Area"); + header.createCell(2).setCellValue("Type"); + header.createCell(3).setCellValue("Cluster"); + header.createCell(4).setCellValue("Category"); + header.createCell(5).setCellValue("2025_01"); + var row = sheet.createRow(1); + row.createCell(0).setCellValue(0.0); + row.createCell(1).setCellValue("FR"); + row.createCell(2).setCellValue("CCGT"); + row.createCell(3).setCellValue("Cluster1"); + row.createCell(4).setCellValue("power"); + row.createCell(5).setCellValue("not_a_number"); + wb.write(out); + return out.toByteArray(); + } + }); + when(areaRepository.findAllByStudyId(any())).thenReturn(List.of(AreaEntity.builder().id(1).name("FR").build())); + assertThrows(BusinessException.class, () -> + thermalFileProcessorService.buildThermalClusterCapacityValuesList(file, "2025", true, "FR", "CCGT", 1) + ); + } + + @Test + void buildThermalClusterCapacityValuesList_shouldThrowBusinessExceptionWhenCellTypeIsUnsupported(@TempDir Path tempDir) throws Exception { + var file = mockExcelFile(tempDir, "test.xlsx", () -> { + try (var out = new ByteArrayOutputStream(); var wb = new XSSFWorkbook()) { + var sheet = wb.createSheet("Sheet1"); + var header = sheet.createRow(0); + header.createCell(0).setCellValue("ToUse"); + header.createCell(1).setCellValue("Area"); + header.createCell(2).setCellValue("Type"); + header.createCell(3).setCellValue("Cluster"); + header.createCell(4).setCellValue("Category"); + header.createCell(5).setCellValue("2025_01"); + var row = sheet.createRow(1); + row.createCell(0).setCellValue(0.0); + row.createCell(1).setCellValue("FR"); + row.createCell(2).setCellValue("CCGT"); + row.createCell(3).setCellValue("Cluster1"); + row.createCell(4).setCellValue("power"); + row.createCell(5).setCellValue(true); // boolean type + wb.write(out); + return out.toByteArray(); + } + }); + when(areaRepository.findAllByStudyId(any())).thenReturn(List.of(AreaEntity.builder().id(1).name("FR").build())); + assertThrows(BusinessException.class, () -> + thermalFileProcessorService.buildThermalClusterCapacityValuesList(file, "2025", true, "FR", "CCGT", 1) + ); + } + + @Test + void buildThermalClusterCapacityValuesList_shouldProcessAllAreasWhenAreaIsOTHERS(@TempDir Path tempDir) throws Exception { + var file = mockExcelFile(tempDir, "test.xlsx", () -> { + try (var out = new ByteArrayOutputStream(); var wb = new XSSFWorkbook()) { + var sheet = wb.createSheet("Sheet1"); + var header = sheet.createRow(0); + header.createCell(0).setCellValue("ToUse"); + header.createCell(1).setCellValue("Area"); + header.createCell(2).setCellValue("Type"); + header.createCell(3).setCellValue("Cluster"); + header.createCell(4).setCellValue("Category"); + // Add a non-horizon column (should be ignored) + header.createCell(5).setCellValue("2024_12"); + // Add horizon columns + for (int i = 1; i <= 12; i++) { + header.createCell(5 + i).setCellValue(String.format("2025_%02d", i)); + } + // FR/Cluster1 - POWER (toUse = 0.0) + var row1 = sheet.createRow(1); + row1.createCell(0).setCellValue(0.0); // ToUse + row1.createCell(1).setCellValue("FR"); + row1.createCell(2).setCellValue("CCGT"); + row1.createCell(3).setCellValue("Cluster1"); + row1.createCell(4).setCellValue("power"); + row1.createCell(5).setCellValue(999.0); // 2024_12, should be ignored + for (int i = 1; i <= 12; i++) { + row1.createCell(5 + i).setCellValue(100 + i); + } + // FR/Cluster1 - NUMBER (toUse = 0.0, must match POWER) + var row2 = sheet.createRow(2); + row2.createCell(0).setCellValue(0.0); // ToUse (was 1.0, now 0.0) + row2.createCell(1).setCellValue("FR"); + row2.createCell(2).setCellValue("CCGT"); + row2.createCell(3).setCellValue("Cluster1"); + row2.createCell(4).setCellValue("number"); + row2.createCell(5).setCellValue(888.0); // 2024_12, should be ignored + for (int i = 1; i <= 12; i++) { + row2.createCell(5 + i).setCellValue(10 + i); + } + // DE/Cluster2 - POWER + var row3 = sheet.createRow(3); + row3.createCell(0).setCellValue(0.0); + row3.createCell(1).setCellValue("DE"); + row3.createCell(2).setCellValue("CCGT"); + row3.createCell(3).setCellValue("Cluster2"); + row3.createCell(4).setCellValue("power"); + for (int i = 1; i <= 12; i++) { + row3.createCell(5 + i).setCellValue(200 + i); + } + // DE/Cluster2 - NUMBER + var row4 = sheet.createRow(4); + row4.createCell(0).setCellValue(0.0); + row4.createCell(1).setCellValue("DE"); + row4.createCell(2).setCellValue("CCGT"); + row4.createCell(3).setCellValue("Cluster2"); + row4.createCell(4).setCellValue("number"); + for (int i = 1; i <= 12; i++) { + row4.createCell(5 + i).setCellValue(20 + i); + } + // Row with different technology (should be ignored) + var row5 = sheet.createRow(5); + row5.createCell(0).setCellValue(0.0); + row5.createCell(1).setCellValue("FR"); + row5.createCell(2).setCellValue("NUCLEAR"); + row5.createCell(3).setCellValue("ClusterX"); + row5.createCell(4).setCellValue("power"); + for (int i = 1; i <= 12; i++) { + row5.createCell(5 + i).setCellValue(300 + i); + } + wb.write(out); + return out.toByteArray(); + } + }); + + when(areaRepository.findAllByStudyId(any())) + .thenReturn(List.of( + AreaEntity.builder().id(1).name("FR").build(), + AreaEntity.builder().id(2).name("DE").build() + )); + when(thermalClusterRefRepository.findAll()).thenReturn(List.of()); + var tech = ThermalTechnology.builder().name("CCGT").build(); + when(thermalTechnologyRepository.findThermalTechnologyByName("CCGT")).thenReturn(Optional.of(tech)); + when(thermalClusterRefRepository.save(any())).thenAnswer(inv -> { + ThermalClusterRef ref = inv.getArgument(0); + ref.setId(1); + return ref; + }); + + var OTHERS_AREA = "OTHERS"; + var dto = thermalFileProcessorService.buildThermalClusterCapacityValuesList( + file, "2025", true, OTHERS_AREA, "CCGT", 1 + ); + + assertTrue(dto.getThermalClusterCapacities().stream().anyMatch(e -> "FR".equals(e.getArea()))); + assertTrue(dto.getThermalClusterCapacities().stream().anyMatch(e -> "DE".equals(e.getArea()))); + assertTrue(dto.getThermalClusterCapacities().stream().noneMatch(e -> "NUCLEAR".equals(e.getThermalClusterRef().getThermalTechnology().getName()))); + assertTrue(dto.getThermalClusterCapacities().stream().noneMatch(e -> "2024_12".equals(e.getMonthYear()))); } + + @Test void isCellInHorizon_shouldReturnTrueWhenMonthIsInSecondHalfOfHorizonYear() { String monthYear = "2025_07"; diff --git a/src/test/java/com/rte_france/antares/datamanager_back/service/TrajectoryServiceImplTest.java b/src/test/java/com/rte_france/antares/datamanager_back/service/TrajectoryServiceImplTest.java index 710e4ac6..30121e9d 100644 --- a/src/test/java/com/rte_france/antares/datamanager_back/service/TrajectoryServiceImplTest.java +++ b/src/test/java/com/rte_france/antares/datamanager_back/service/TrajectoryServiceImplTest.java @@ -13,10 +13,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; +import org.mockito.*; import org.springframework.http.HttpStatus; import java.io.IOException; @@ -170,6 +167,22 @@ void throwsExceptionWhenTrajectoryToUseIsNull() { assertEquals(HttpStatus.BAD_REQUEST, exception.getHttpStatus()); } + @Test + void processThermalCapacityTrajectory_shouldThrowExceptionWhenFileNameDoesNotStartWithThermal() { + String trajectoryToUse = "invalid_file"; + String horizon = "2023-2024"; + Integer studyId = 1; + boolean isCivilYear = true; + String area = "BE"; + String technology = "CCGT"; + + BusinessException exception = assertThrows(BusinessException.class, () -> + trajectoryService.processThermalCapacityTrajectory(trajectoryToUse, horizon, studyId, isCivilYear, area, technology)); + + assertEquals("The trajectory file name must start with 'thermal_'", exception.getMessage()); + assertEquals(HttpStatus.BAD_REQUEST, exception.getHttpStatus()); + } + @Test void findTrajectoriesByTypeAndFileNameContainsFromDB_returnsEntitiesWhenExist() { List expectedEntities = List.of(new TrajectoryEntity()); diff --git a/src/test/java/com/rte_france/antares/datamanager_back/util/ExcelFilesValidators/AreaFileValidatorTest.java b/src/test/java/com/rte_france/antares/datamanager_back/util/ExcelFilesValidators/AreaFileValidatorTest.java index b6e05f6b..ba74b064 100644 --- a/src/test/java/com/rte_france/antares/datamanager_back/util/ExcelFilesValidators/AreaFileValidatorTest.java +++ b/src/test/java/com/rte_france/antares/datamanager_back/util/ExcelFilesValidators/AreaFileValidatorTest.java @@ -268,7 +268,7 @@ void checkColumnsDuplicated() throws IOException { Sheet sheet = workbook.getSheet("2035-2036"); BusinessException exception = assertThrows(BusinessException.class, - () -> ExcelCommonValidator.checkForDuplicateValues(sheet, "areas", tempFile,"2035-2036", false, TrajectoryType.AREA.name())); + () -> ExcelCommonValidator.checkForDuplicateValues(sheet, "areas","2035-2036", false, TrajectoryType.AREA.name())); assertAll( () -> assertEquals("Duplicate value for {0}(s): {1} for {2} trajectory",