diff --git a/.gitignore b/.gitignore index ad28b8c..a938efe 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ hs_err_pid* # test generated files src/test/resources/OUT/* /src/test/resources/DONE/* +/src/test/resources/genesis_deleted_schedules/* diff --git a/pom.xml b/pom.xml index aeaec8a..f667512 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ 21 2.6.0 1.6.2 - 7.19.0 + 7.20.0 0.8.12 jacoco @@ -98,6 +98,11 @@ jackson-databind ${jackson.version} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + diff --git a/src/main/java/fr/insee/genesis/Constants.java b/src/main/java/fr/insee/genesis/Constants.java index 73ab856..f1711c2 100644 --- a/src/main/java/fr/insee/genesis/Constants.java +++ b/src/main/java/fr/insee/genesis/Constants.java @@ -11,6 +11,8 @@ public class Constants { public static final String FILTER_RESULT_PREFIX = "FILTER_RESULT_"; public static final String MISSING_SUFFIX = "_MISSING"; private static final String[] ENO_VARIABLES = {"COMMENT_QE","COMMENT_UE","HEURE_REMPL","MIN_REMPL"}; + + public static final String MONGODB_SCHEDULE_COLLECTION_NAME = "schedules"; public static final String LOOP_NAME_PREFIX = "BOUCLE"; public static final String MONGODB_RESPONSE_COLLECTION_NAME = "responses"; public static final String VOLUMETRY_FOLDER_NAME = "genesis_volumetries"; @@ -18,6 +20,8 @@ public class Constants { public static final String VOLUMETRY_FILE_DATE_FORMAT = "yyyy_MM_dd"; public static final int VOLUMETRY_FILE_EXPIRATION_DAYS = 30; + public static final String SCHEDULE_ARCHIVE_FOLDER_NAME = "genesis_deleted_schedules"; + // XML sequential reading parameters public static final int MAX_FILE_SIZE_UNTIL_SEQUENTIAL = 200; // In megabytes diff --git a/src/main/java/fr/insee/genesis/controller/rest/ScheduleController.java b/src/main/java/fr/insee/genesis/controller/rest/ScheduleController.java index ba7d637..d36effc 100644 --- a/src/main/java/fr/insee/genesis/controller/rest/ScheduleController.java +++ b/src/main/java/fr/insee/genesis/controller/rest/ScheduleController.java @@ -1,6 +1,9 @@ package fr.insee.genesis.controller.rest; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import fr.insee.genesis.Constants; +import fr.insee.genesis.domain.model.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.schedule.ScheduleModel; import fr.insee.genesis.domain.model.schedule.ServiceToCall; import fr.insee.genesis.domain.model.schedule.TrustParameters; @@ -22,8 +25,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.time.LocalDateTime; +import java.util.HashSet; import java.util.List; +import java.util.Set; @RequestMapping(path = "/schedule") @Controller @@ -75,11 +84,19 @@ public ResponseEntity addSchedule( useSignature ); log.info("New schedule request for survey {} with encryption", surveyName); - scheduleApiPort.addSchedule(surveyName, serviceToCall, frequency, scheduleBeginDate, scheduleEndDate, + scheduleApiPort.addSchedule(surveyName, + serviceToCall == null ? ServiceToCall.MAIN : serviceToCall, + frequency, + scheduleBeginDate, + scheduleEndDate, trustParameters); }else{ log.info("New schedule request for survey {}", surveyName); - scheduleApiPort.addSchedule(surveyName, serviceToCall, frequency, scheduleBeginDate, scheduleEndDate, + scheduleApiPort.addSchedule(surveyName, + serviceToCall == null ? ServiceToCall.MAIN : serviceToCall, + frequency, + scheduleBeginDate, + scheduleEndDate, null); } @@ -124,4 +141,36 @@ public ResponseEntity setSurveyLastExecution( } return ResponseEntity.ok().build(); } + + @Operation(summary = "Delete expired schedules") + @DeleteMapping(path = "/delete/expired-schedules") + public ResponseEntity deleteExpiredSchedules() throws NotFoundException, IOException { + Set storedSurveySchedulesNames = new HashSet<>(); + for(ScheduleModel scheduleModel : scheduleApiPort.getAllSchedules()){ + storedSurveySchedulesNames.add(scheduleModel.getSurveyName()); + } + for (String surveyScheduleName : storedSurveySchedulesNames) { + List deletedKraftwerkExecutionSchedules = scheduleApiPort.deleteExpiredSchedules(surveyScheduleName); + //Save in JSON log + if(!deletedKraftwerkExecutionSchedules.isEmpty()) { + Path jsonLogPath = Path.of(fileUtils.getLogFolder(), Constants.SCHEDULE_ARCHIVE_FOLDER_NAME, + surveyScheduleName + ".json"); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + String jsonToWrite = objectMapper.writeValueAsString(deletedKraftwerkExecutionSchedules); + if(Files.exists(jsonLogPath)){ + //Remove last ] and append survey + StringBuilder content = new StringBuilder(Files.readString(jsonLogPath)); + content.setCharAt(content.length()-1, ','); + content.append(jsonToWrite, 1, jsonToWrite.length()-1); + content.append(']'); + Files.write(jsonLogPath, content.toString().getBytes(), StandardOpenOption.TRUNCATE_EXISTING); + }else { + Files.createDirectories(jsonLogPath.getParent()); + Files.write(jsonLogPath, jsonToWrite.getBytes()); + } + } + } + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/fr/insee/genesis/domain/model/schedule/KraftwerkExecutionSchedule.java b/src/main/java/fr/insee/genesis/domain/model/schedule/KraftwerkExecutionSchedule.java index c9da8a9..683d8c5 100644 --- a/src/main/java/fr/insee/genesis/domain/model/schedule/KraftwerkExecutionSchedule.java +++ b/src/main/java/fr/insee/genesis/domain/model/schedule/KraftwerkExecutionSchedule.java @@ -1,5 +1,6 @@ package fr.insee.genesis.domain.model.schedule; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Data; @@ -12,7 +13,10 @@ public class KraftwerkExecutionSchedule { private ServiceToCall serviceToCall; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime scheduleBeginDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime scheduleEndDate; private TrustParameters trustParameters; diff --git a/src/main/java/fr/insee/genesis/domain/ports/api/ScheduleApiPort.java b/src/main/java/fr/insee/genesis/domain/ports/api/ScheduleApiPort.java index 4bbb09c..91019b2 100644 --- a/src/main/java/fr/insee/genesis/domain/ports/api/ScheduleApiPort.java +++ b/src/main/java/fr/insee/genesis/domain/ports/api/ScheduleApiPort.java @@ -1,5 +1,6 @@ package fr.insee.genesis.domain.ports.api; +import fr.insee.genesis.domain.model.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.schedule.ScheduleModel; import fr.insee.genesis.domain.model.schedule.ServiceToCall; import fr.insee.genesis.domain.model.schedule.TrustParameters; @@ -22,6 +23,8 @@ void addSchedule(String surveyName, void deleteSchedule(String surveyName) throws NotFoundException; + List deleteExpiredSchedules(String surveyName) throws NotFoundException; + void updateLastExecutionName(String surveyName, LocalDateTime newDate) throws NotFoundException; long countSchedules(); diff --git a/src/main/java/fr/insee/genesis/domain/ports/spi/SchedulePersistencePort.java b/src/main/java/fr/insee/genesis/domain/ports/spi/SchedulePersistencePort.java index 9320c67..8e3f857 100644 --- a/src/main/java/fr/insee/genesis/domain/ports/spi/SchedulePersistencePort.java +++ b/src/main/java/fr/insee/genesis/domain/ports/spi/SchedulePersistencePort.java @@ -1,5 +1,6 @@ package fr.insee.genesis.domain.ports.spi; +import fr.insee.genesis.domain.model.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.schedule.ScheduleModel; import java.util.List; @@ -14,4 +15,6 @@ public interface SchedulePersistencePort { void deleteBySurveyName(String surveyName); long countSchedules(); + + public List removeExpiredSchedules(ScheduleModel scheduleModel); } diff --git a/src/main/java/fr/insee/genesis/domain/service/schedule/ScheduleService.java b/src/main/java/fr/insee/genesis/domain/service/schedule/ScheduleService.java index 3c0cdc4..f022a0d 100644 --- a/src/main/java/fr/insee/genesis/domain/service/schedule/ScheduleService.java +++ b/src/main/java/fr/insee/genesis/domain/service/schedule/ScheduleService.java @@ -79,6 +79,30 @@ public void deleteSchedule(String surveyName) throws NotFoundException { schedulePersistencePort.deleteBySurveyName(surveyName); } + @Override + public List deleteExpiredSchedules(String surveyName) throws NotFoundException { + List scheduleModels = schedulePersistencePort.findBySurveyName(surveyName); + if (scheduleModels.isEmpty()) { + throw new NotFoundException(); + } + List deletedKraftwerkExecutionSchedules = new ArrayList<>(); + for (ScheduleModel scheduleModel : scheduleModels) { + deletedKraftwerkExecutionSchedules.addAll(schedulePersistencePort.removeExpiredSchedules(scheduleModel)); + //Delete schedule if empty kraftwerkExecutionScheduleList + schedulePersistencePort.findBySurveyName(surveyName) + .stream() + .filter(storedSurveySchedule -> storedSurveySchedule.getKraftwerkExecutionScheduleList().isEmpty()) + .forEach(storedSurveySchedule -> { + try { + deleteSchedule(surveyName); + } catch (NotFoundException e) { + log.error("Tried to delete schedule for {} but wasn't found !", surveyName); + } + }); + } + return deletedKraftwerkExecutionSchedules; + } + @Override public void updateLastExecutionName(String surveyName, LocalDateTime newDate) throws NotFoundException { List scheduleModels = schedulePersistencePort.findBySurveyName(surveyName); diff --git a/src/main/java/fr/insee/genesis/infrastructure/adapter/ScheduleMongoAdapter.java b/src/main/java/fr/insee/genesis/infrastructure/adapter/ScheduleMongoAdapter.java index b7d8f22..00afd80 100644 --- a/src/main/java/fr/insee/genesis/infrastructure/adapter/ScheduleMongoAdapter.java +++ b/src/main/java/fr/insee/genesis/infrastructure/adapter/ScheduleMongoAdapter.java @@ -1,21 +1,34 @@ package fr.insee.genesis.infrastructure.adapter; +import fr.insee.genesis.Constants; +import fr.insee.genesis.domain.model.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.schedule.ScheduleModel; import fr.insee.genesis.domain.ports.spi.SchedulePersistencePort; import fr.insee.genesis.infrastructure.mappers.ScheduleDocumentMapper; import fr.insee.genesis.infrastructure.repository.ScheduleMongoDBRepository; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; +import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; @Service +@Slf4j public class ScheduleMongoAdapter implements SchedulePersistencePort { private final ScheduleMongoDBRepository scheduleMongoDBRepository; + private final MongoTemplate mongoTemplate; + @Autowired - public ScheduleMongoAdapter(ScheduleMongoDBRepository scheduleMongoDBRepository) { + public ScheduleMongoAdapter(ScheduleMongoDBRepository scheduleMongoDBRepository, MongoTemplate mongoTemplate) { this.scheduleMongoDBRepository = scheduleMongoDBRepository; + this.mongoTemplate = mongoTemplate; } @Override @@ -42,4 +55,23 @@ public void deleteBySurveyName(String surveyName) { public long countSchedules() { return scheduleMongoDBRepository.count(); } + + @Override + public List removeExpiredSchedules(ScheduleModel scheduleModel) { + List deletedKraftwerkExecutionSchedules = new ArrayList<>(); + for (KraftwerkExecutionSchedule kraftwerkExecutionScheduleToRemove : + scheduleModel.getKraftwerkExecutionScheduleList().stream().filter( + kraftwerkExecutionSchedule -> kraftwerkExecutionSchedule.getScheduleEndDate().isBefore(LocalDateTime.now()) + ).toList()) { + deletedKraftwerkExecutionSchedules.add(kraftwerkExecutionScheduleToRemove); + Query query = + Query.query(Criteria.where("scheduleEndDate").is(kraftwerkExecutionScheduleToRemove.getScheduleEndDate())); + mongoTemplate.updateMulti(Query.query(Criteria.where("surveyName").is(scheduleModel.getSurveyName())), new Update().pull( + "kraftwerkExecutionScheduleList", query), + Constants.MONGODB_SCHEDULE_COLLECTION_NAME); + log.info("Removed kraftwerk execution schedule on {} because it is expired since {}", scheduleModel.getSurveyName(), + kraftwerkExecutionScheduleToRemove.getScheduleEndDate()); + } + return deletedKraftwerkExecutionSchedules; + } } diff --git a/src/main/java/fr/insee/genesis/infrastructure/utils/FileUtils.java b/src/main/java/fr/insee/genesis/infrastructure/utils/FileUtils.java index e03e95e..155acc3 100644 --- a/src/main/java/fr/insee/genesis/infrastructure/utils/FileUtils.java +++ b/src/main/java/fr/insee/genesis/infrastructure/utils/FileUtils.java @@ -29,9 +29,12 @@ public class FileUtils { private final String specFolderSource; + private final String logFolderSource; + public FileUtils(Config config) { this.dataFolderSource = config.getDataFolderSource(); this.specFolderSource = config.getSpecFolderSource(); + this.logFolderSource = config.getLogFolder(); } /** @@ -188,6 +191,14 @@ public String getKraftwerkOutFolder(String campaign) { return String.format("%s/%s/%s", dataFolderSource, "out", campaign); } + /** + * Get the path of the folder where the log files are stored + * @return Path of the output folder + */ + public String getLogFolder() { + return logFolderSource; + } + /** * Write a text file. * @param filePath Path to the file. diff --git a/src/test/java/fr/insee/genesis/controller/rest/ScheduleModelControllerTest.java b/src/test/java/fr/insee/genesis/controller/rest/ScheduleControllerTest.java similarity index 55% rename from src/test/java/fr/insee/genesis/controller/rest/ScheduleModelControllerTest.java rename to src/test/java/fr/insee/genesis/controller/rest/ScheduleControllerTest.java index 7668234..3dc3278 100644 --- a/src/test/java/fr/insee/genesis/controller/rest/ScheduleModelControllerTest.java +++ b/src/test/java/fr/insee/genesis/controller/rest/ScheduleControllerTest.java @@ -2,9 +2,13 @@ import cucumber.TestConstants; +import fr.insee.genesis.Constants; import fr.insee.genesis.domain.model.schedule.KraftwerkExecutionSchedule; +import fr.insee.genesis.domain.model.schedule.ScheduleModel; import fr.insee.genesis.domain.model.schedule.ServiceToCall; +import fr.insee.genesis.exceptions.NotFoundException; import fr.insee.genesis.infrastructure.document.schedule.ScheduleDocument; +import fr.insee.genesis.infrastructure.mappers.ScheduleDocumentMapper; import fr.insee.genesis.infrastructure.utils.FileUtils; import fr.insee.genesis.stubs.ConfigStub; import fr.insee.genesis.stubs.ScheduleApiPortStub; @@ -13,22 +17,33 @@ import org.junit.jupiter.api.Test; import org.springframework.http.ResponseEntity; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; import java.time.Month; import java.util.ArrayList; import java.util.List; -class ScheduleModelControllerTest { +class ScheduleControllerTest { //Given private static ScheduleController scheduleController; private static ScheduleApiPortStub scheduleApiPortStub; @BeforeEach - void clean() { + void clean() throws IOException { scheduleApiPortStub = new ScheduleApiPortStub(); scheduleController = new ScheduleController(scheduleApiPortStub, new FileUtils(new ConfigStub())); + //Clean genesis_deleted_schedules log folder + if(Files.exists(Path.of(TestConstants.TEST_RESOURCES_DIRECTORY) + .resolve(Constants.SCHEDULE_ARCHIVE_FOLDER_NAME))) { + for (Path filePath : Files.list(Path.of(TestConstants.TEST_RESOURCES_DIRECTORY) + .resolve(Constants.SCHEDULE_ARCHIVE_FOLDER_NAME)).toList()) { + Files.deleteIfExists(filePath); + } + } + scheduleController = new ScheduleController(scheduleApiPortStub, new FileUtils(new ConfigStub())); } @Test @@ -67,6 +82,34 @@ void addScheduleWithoutEncryptionTest() { Assertions.assertThat(scheduleDocument.getKraftwerkExecutionScheduleList().getFirst().getTrustParameters()).isNull(); } + @Test + void addScheduleWithoutEncryptionTest_nullServiceToCall() { + //When + String surveyName = "TESTADDSURVEY"; + ServiceToCall serviceToCall = null; + String frequency = "0 0 6 * * *"; + LocalDateTime scheduleBeginDate = LocalDateTime.now(); + LocalDateTime scheduleEndDate = LocalDateTime.now().plusMonths(1); + + scheduleController.addSchedule(surveyName, serviceToCall, frequency, scheduleBeginDate, scheduleEndDate, + false, "TEST", "TEST", false); + + //Then + Assertions.assertThat(scheduleApiPortStub.mongoStub).filteredOn(scheduleDocument -> + scheduleDocument.getSurveyName().equals(surveyName) + ).isNotEmpty(); + + List mongoStubFiltered = scheduleApiPortStub.mongoStub.stream().filter(scheduleDocument -> + scheduleDocument.getSurveyName().equals(surveyName)).toList(); + + ScheduleDocument scheduleDocument = mongoStubFiltered.getFirst(); + + Assertions.assertThat(scheduleDocument.getKraftwerkExecutionScheduleList()).isNotEmpty(); + Assertions.assertThat(scheduleDocument.getKraftwerkExecutionScheduleList().getFirst().getServiceToCall()).isEqualTo(ServiceToCall.MAIN); + Assertions.assertThat(scheduleDocument.getKraftwerkExecutionScheduleList().getFirst().getFrequency()).isEqualTo(frequency); + Assertions.assertThat(scheduleDocument.getKraftwerkExecutionScheduleList().getFirst().getTrustParameters()).isNull(); + } + @Test void addScheduleWithEncryptionTest() { //When @@ -248,4 +291,146 @@ void deleteScheduleTest(){ scheduleDocument.getSurveyName().equals("TESTSURVEY") ).isEmpty(); } + + @Test + void deleteExpiredScheduleTest_execution() throws NotFoundException, IOException { + //Given + ScheduleModel scheduleModel = new ScheduleModel( + "TESTSURVEYADDED", + null, + new ArrayList<>() + ); + KraftwerkExecutionSchedule kraftwerkExecutionSchedule = new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.of(2000, Month.JANUARY, 1, 1, 1, 1), + LocalDateTime.of(2000, Month.DECEMBER, 1, 1, 1, 1), + null + ); + scheduleModel.getKraftwerkExecutionScheduleList().add(kraftwerkExecutionSchedule); + kraftwerkExecutionSchedule = new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.of(2023, Month.FEBRUARY, 1, 1, 1, 1), + LocalDateTime.of(5023, Month.DECEMBER, 1, 1, 1, 1), + null + ); + scheduleModel.getKraftwerkExecutionScheduleList().add(kraftwerkExecutionSchedule); + scheduleApiPortStub.mongoStub.add(ScheduleDocumentMapper.INSTANCE.modelToDocument(scheduleModel)); + + //When + scheduleController.deleteExpiredSchedules(); + + //Then + //Expired schedule deleted + Assertions.assertThat(scheduleApiPortStub.mongoStub).filteredOn(scheduleDocument -> + scheduleDocument.getSurveyName().equals("TESTSURVEYADDED") + ).isNotEmpty(); + Assertions.assertThat(scheduleApiPortStub.mongoStub.stream().filter(scheduleDocument -> + scheduleDocument.getSurveyName().equals("TESTSURVEYADDED")).toList().getFirst().getKraftwerkExecutionScheduleList() + ).isNotEmpty().hasSize(1); + + //Expired schedule to log json file + Assertions.assertThat(Path.of(TestConstants.TEST_RESOURCES_DIRECTORY) + .resolve(Constants.SCHEDULE_ARCHIVE_FOLDER_NAME) + .resolve("TESTSURVEYADDED.json") + .toFile()).exists().content().isNotEmpty().contains("2000").doesNotContain("5023"); + } + + @Test + void deleteExpiredScheduleTest_wholeSurvey() throws NotFoundException, IOException { + //Given + ScheduleModel scheduleModel = new ScheduleModel( + "TESTSURVEYADDED", + null, + new ArrayList<>() + ); + KraftwerkExecutionSchedule kraftwerkExecutionSchedule = new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.of(2001, Month.JANUARY, 1, 1, 1, 1), + LocalDateTime.of(2001, Month.DECEMBER, 1, 1, 1, 1), + null + ); + scheduleModel.getKraftwerkExecutionScheduleList().add(kraftwerkExecutionSchedule); + kraftwerkExecutionSchedule = new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.of(2002, Month.FEBRUARY, 1, 1, 1, 1), + LocalDateTime.of(2002, Month.DECEMBER, 1, 1, 1, 1), + null + ); + scheduleModel.getKraftwerkExecutionScheduleList().add(kraftwerkExecutionSchedule); + scheduleApiPortStub.mongoStub.add(ScheduleDocumentMapper.INSTANCE.modelToDocument(scheduleModel)); + + //When + scheduleController.deleteExpiredSchedules(); + + //Then + //Expired schedule document deleted + Assertions.assertThat(scheduleApiPortStub.mongoStub).filteredOn(scheduleDocument -> + scheduleDocument.getSurveyName().equals("TESTSURVEYADDED") + ).isEmpty(); + + //Expired schedule to log json file + Assertions.assertThat(Path.of(TestConstants.TEST_RESOURCES_DIRECTORY) + .resolve(Constants.SCHEDULE_ARCHIVE_FOLDER_NAME) + .resolve("TESTSURVEYADDED.json") + .toFile()).exists().content().isNotEmpty().contains("2001","2002"); + } + + @Test + void deleteExpiredScheduleTest_appendLog() throws NotFoundException, IOException { + //Given + ScheduleModel scheduleModel = new ScheduleModel( + "TESTSURVEYADDED2", + null, + new ArrayList<>() + ); + KraftwerkExecutionSchedule kraftwerkExecutionSchedule = new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.of(2000, Month.JANUARY, 1, 1, 1, 1), + LocalDateTime.of(2000, Month.DECEMBER, 1, 1, 1, 1), + null + ); + scheduleModel.getKraftwerkExecutionScheduleList().add(kraftwerkExecutionSchedule); + kraftwerkExecutionSchedule = new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.of(2023, Month.FEBRUARY, 1, 1, 1, 1), + LocalDateTime.of(5023, Month.DECEMBER, 1, 1, 1, 1), + null + ); + scheduleModel.getKraftwerkExecutionScheduleList().add(kraftwerkExecutionSchedule); + scheduleApiPortStub.mongoStub.add(ScheduleDocumentMapper.INSTANCE.modelToDocument(scheduleModel)); + + //When + scheduleController.deleteExpiredSchedules(); + kraftwerkExecutionSchedule = new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.of(2001, Month.FEBRUARY, 1, 1, 1, 1), + LocalDateTime.of(2001, Month.DECEMBER, 1, 1, 1, 1), + null + ); + scheduleModel.getKraftwerkExecutionScheduleList().add(kraftwerkExecutionSchedule); + scheduleApiPortStub.mongoStub.add(ScheduleDocumentMapper.INSTANCE.modelToDocument(scheduleModel)); + scheduleController.deleteExpiredSchedules(); + + //Then + //Expired schedules deleted + Assertions.assertThat(scheduleApiPortStub.mongoStub).filteredOn(scheduleDocument -> + scheduleDocument.getSurveyName().equals("TESTSURVEYADDED2") + ).isNotEmpty(); + Assertions.assertThat(scheduleApiPortStub.mongoStub.stream().filter(scheduleDocument -> + scheduleDocument.getSurveyName().equals("TESTSURVEYADDED2")).toList().getFirst().getKraftwerkExecutionScheduleList() + ).isNotEmpty().hasSize(1); + + //Expired schedules to only one log json file + Assertions.assertThat(Path.of(TestConstants.TEST_RESOURCES_DIRECTORY) + .resolve(Constants.SCHEDULE_ARCHIVE_FOLDER_NAME) + .resolve("TESTSURVEYADDED2.json") + .toFile()).exists().content().isNotEmpty().contains("2000","2001"); + } } diff --git a/src/test/java/fr/insee/genesis/domain/service/ScheduleServiceTest.java b/src/test/java/fr/insee/genesis/domain/service/ScheduleServiceTest.java index e11e767..6c1736c 100644 --- a/src/test/java/fr/insee/genesis/domain/service/ScheduleServiceTest.java +++ b/src/test/java/fr/insee/genesis/domain/service/ScheduleServiceTest.java @@ -127,4 +127,54 @@ void countSchedules_test(){ Assertions.assertThat(scheduleService.countSchedules()).isEqualTo(1); } + @Test + void removeExpiredSchedules_test_existing_schedule() throws NotFoundException { + //Given + //Expired schedule + schedulePersistencePortStub.getMongoStub().getFirst().getKraftwerkExecutionScheduleList().add(new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.MIN, + LocalDateTime.of(2000,1,1,1,1,1), + null + )); + + //When + scheduleService.deleteExpiredSchedules("TEST"); + + //Then + //Execution schedule deleted + Assertions.assertThat(schedulePersistencePortStub.getMongoStub()).hasSize(1); + Assertions.assertThat(schedulePersistencePortStub.getMongoStub().getFirst().getKraftwerkExecutionScheduleList()).hasSize(1); + Assertions.assertThat(schedulePersistencePortStub.getMongoStub().getFirst().getKraftwerkExecutionScheduleList().getFirst().getScheduleEndDate()) + .isEqualTo(LocalDateTime.MAX); + } + @Test + void removeExpiredSchedules_test_delete_document() throws NotFoundException { + //Given + //Expired schedule + new survey + List kraftwerkExecutionScheduleList = new ArrayList<>(); + kraftwerkExecutionScheduleList.add(new KraftwerkExecutionSchedule( + "0 0 6 * * *", + ServiceToCall.MAIN, + LocalDateTime.MIN, + LocalDateTime.of(2000,1,1,1,1,1), + null + )); + schedulePersistencePortStub.getMongoStub().add(new ScheduleDocument( + "TEST2", + kraftwerkExecutionScheduleList + )); + + //When + scheduleService.deleteExpiredSchedules("TEST2"); + + //Then + //Survey schedule document deleted + Assertions.assertThat(schedulePersistencePortStub.getMongoStub()).hasSize(1); + Assertions.assertThat(schedulePersistencePortStub.getMongoStub().stream().filter( + scheduleDocument -> scheduleDocument.getSurveyName().equals("TEST2") + ).toList()).isEmpty(); + + } } diff --git a/src/test/java/fr/insee/genesis/stubs/ScheduleApiPortStub.java b/src/test/java/fr/insee/genesis/stubs/ScheduleApiPortStub.java index f339acd..4c3f8d8 100644 --- a/src/test/java/fr/insee/genesis/stubs/ScheduleApiPortStub.java +++ b/src/test/java/fr/insee/genesis/stubs/ScheduleApiPortStub.java @@ -103,6 +103,23 @@ public void deleteSchedule(String surveyName) throws NotFoundException { }else throw new NotFoundException(); } + @Override + public List deleteExpiredSchedules(String surveyName) throws NotFoundException { + List mongoStubFiltered = mongoStub.stream().filter(scheduleDocument -> + scheduleDocument.getSurveyName().equals(surveyName)).toList(); + if(mongoStubFiltered.isEmpty()){ + throw new NotFoundException(); + } + List deletedKraftwerkExecutionSchedules = new ArrayList<>(); + for(ScheduleDocument scheduleDocument : mongoStubFiltered){ + deletedKraftwerkExecutionSchedules.addAll(removeExpiredSchedules(scheduleDocument)); + if(scheduleDocument.getKraftwerkExecutionScheduleList().isEmpty()){ + mongoStub.remove(scheduleDocument); + } + } + return deletedKraftwerkExecutionSchedules; + } + @Override public void updateLastExecutionName(String surveyName, LocalDateTime newDate) throws NotFoundException { List mongoStubFiltered = mongoStub.stream().filter(scheduleDocument -> @@ -117,4 +134,18 @@ public void updateLastExecutionName(String surveyName, LocalDateTime newDate) th public long countSchedules() { return mongoStub.size(); } + + public List removeExpiredSchedules(ScheduleDocument scheduleDocument) { + List deletedKraftwerkExecutionSchedules = new ArrayList<>( + scheduleDocument.getKraftwerkExecutionScheduleList().stream().filter( + kraftwerkExecutionSchedule1 -> + kraftwerkExecutionSchedule1.getScheduleEndDate().isBefore(LocalDateTime.now())).toList() + ); + + scheduleDocument.getKraftwerkExecutionScheduleList().removeIf( + kraftwerkExecutionSchedule1 -> + kraftwerkExecutionSchedule1.getScheduleEndDate().isBefore(LocalDateTime.now()) + ); + return deletedKraftwerkExecutionSchedules; + } } diff --git a/src/test/java/fr/insee/genesis/stubs/SchedulePersistencePortStub.java b/src/test/java/fr/insee/genesis/stubs/SchedulePersistencePortStub.java index 056c206..58af7c0 100644 --- a/src/test/java/fr/insee/genesis/stubs/SchedulePersistencePortStub.java +++ b/src/test/java/fr/insee/genesis/stubs/SchedulePersistencePortStub.java @@ -1,15 +1,19 @@ package fr.insee.genesis.stubs; +import fr.insee.genesis.domain.model.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.schedule.ScheduleModel; import fr.insee.genesis.domain.ports.spi.SchedulePersistencePort; -import fr.insee.genesis.infrastructure.mappers.ScheduleDocumentMapper; import fr.insee.genesis.infrastructure.document.schedule.ScheduleDocument; +import fr.insee.genesis.infrastructure.mappers.ScheduleDocumentMapper; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Getter +@Slf4j public class SchedulePersistencePortStub implements SchedulePersistencePort { List mongoStub = new ArrayList<>(); @@ -37,4 +41,20 @@ public void deleteBySurveyName(String surveyName) { public long countSchedules() { return mongoStub.size(); } -} + + @Override + public List removeExpiredSchedules(ScheduleModel scheduleModel) { + List kraftwerkExecutionSchedulesToRemove = new ArrayList<>(scheduleModel.getKraftwerkExecutionScheduleList().stream().filter( + kraftwerkExecutionSchedule -> kraftwerkExecutionSchedule.getScheduleEndDate().isBefore(LocalDateTime.now()) + ).toList()); + for (KraftwerkExecutionSchedule kraftwerkExecutionScheduleToRemove : kraftwerkExecutionSchedulesToRemove){ + scheduleModel.getKraftwerkExecutionScheduleList().remove(kraftwerkExecutionScheduleToRemove); + log.info("Removed kraftwerk execution schedule on {} because it is expired since {}", scheduleModel.getSurveyName(), + kraftwerkExecutionScheduleToRemove.getScheduleEndDate()); + } + //Update mongo stub + mongoStub.removeIf(scheduleDocument -> scheduleDocument.getSurveyName().equals(scheduleModel.getSurveyName())); + mongoStub.add(ScheduleDocumentMapper.INSTANCE.modelToDocument(scheduleModel)); + return kraftwerkExecutionSchedulesToRemove; + } +} \ No newline at end of file