From 5028d096d4f39664278dd2003187b5bfa63b0107 Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Mon, 18 May 2026 15:54:15 +0200 Subject: [PATCH 1/3] fix: delete only expired V2 schedules from dataProcessingContext --- .../DataProcessingContextPersistancePort.java | 4 +- .../context/DataProcessingContextService.java | 48 +++++++++----- .../DataProcessingContextMongoAdapter.java | 53 +++++++++------ ...DataProcessingContextMongoAdapterTest.java | 64 ++++++++++++------- 4 files changed, 109 insertions(+), 60 deletions(-) diff --git a/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java b/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java index be618b23..8ebfb0b6 100644 --- a/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java +++ b/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java @@ -1,7 +1,7 @@ package fr.insee.genesis.domain.ports.spi; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; -import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionSchedule; +import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; import fr.insee.genesis.infrastructure.document.context.DataProcessingContextDocument; import java.io.IOException; @@ -21,7 +21,7 @@ public interface DataProcessingContextPersistancePort { long count(); - List removeExpiredSchedules(DataProcessingContextModel dataProcessingContextModel) throws IOException; + List removeExpiredSchedules(DataProcessingContextModel dataProcessingContextModel) throws IOException; List findAllByReview(boolean withReview); } diff --git a/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java b/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java index 001bbc92..eaf0cf69 100644 --- a/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java +++ b/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java @@ -6,7 +6,6 @@ import fr.insee.genesis.controller.dto.KraftwerkExecutionScheduleInput; import fr.insee.genesis.controller.dto.rawdata.ScheduleResponseDto; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; -import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; import fr.insee.genesis.domain.model.surveyunit.SurveyUnitModel; import fr.insee.genesis.domain.ports.api.DataProcessingContextApiPort; @@ -266,33 +265,50 @@ public List getAllSchedulesV2() { @Override public void deleteExpiredSchedules(String logFolder) throws GenesisException { List dataProcessingContextModels = - DataProcessingContextMapper.INSTANCE.listDocumentToListModel(dataProcessingContextPersistancePort.findAll()); - for(DataProcessingContextModel context : dataProcessingContextModels){ + DataProcessingContextMapper.INSTANCE.listDocumentToListModel( + dataProcessingContextPersistancePort.findAll() + ); + + for (DataProcessingContextModel context : dataProcessingContextModels) { try { - List deletedKraftwerkExecutionSchedules = dataProcessingContextPersistancePort.removeExpiredSchedules(context); - //Save in JSON log - if(!deletedKraftwerkExecutionSchedules.isEmpty()) { + List deletedKraftwerkExecutionSchedules = + dataProcessingContextPersistancePort.removeExpiredSchedules(context); + + // Save in JSON log + if (!deletedKraftwerkExecutionSchedules.isEmpty()) { String scheduleName = context.getCollectionInstrumentId(); - Path jsonLogPath = Path.of(logFolder, Constants.SCHEDULE_ARCHIVE_FOLDER_NAME, - scheduleName + ".json"); + Path jsonLogPath = Path.of( + logFolder, + Constants.SCHEDULE_ARCHIVE_FOLDER_NAME, + scheduleName + ".json" + ); + ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); objectMapper.registerModule(new JavaTimeModule()); + String jsonToWrite = objectMapper.writeValueAsString(deletedKraftwerkExecutionSchedules); - if(Files.exists(jsonLogPath)){ - //Remove last ] and append survey + + if (Files.exists(jsonLogPath)) { StringBuilder content = new StringBuilder(Files.readString(jsonLogPath)); - content.setCharAt(content.length()-1, ','); - content.append(jsonToWrite, 1, jsonToWrite.length()-1); + 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.write( + jsonLogPath, + content.toString().getBytes(), + StandardOpenOption.TRUNCATE_EXISTING + ); + } else { Files.createDirectories(jsonLogPath.getParent()); Files.write(jsonLogPath, jsonToWrite.getBytes()); } } } catch (IOException _) { - String name = context.getCollectionInstrumentId(); - throw new GenesisException(HttpStatus.INTERNAL_SERVER_ERROR,String.format("An error occured trying to delete expired schedules for %s",name)); + String name = context.getCollectionInstrumentId(); + throw new GenesisException( + HttpStatus.INTERNAL_SERVER_ERROR, + String.format("An error occured trying to delete expired schedules for %s", name) + ); } } } diff --git a/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java b/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java index bc32744a..3b277992 100644 --- a/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java +++ b/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java @@ -2,7 +2,7 @@ import fr.insee.genesis.Constants; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; -import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionSchedule; +import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; import fr.insee.genesis.domain.ports.spi.DataProcessingContextPersistancePort; import fr.insee.genesis.infrastructure.document.context.DataProcessingContextDocument; import fr.insee.genesis.infrastructure.mappers.DataProcessingContextMapper; @@ -16,10 +16,9 @@ import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; -import java.io.IOException; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; +import java.util.Optional; @Service @Qualifier("dataProcessingContextMongoAdapter") @@ -75,23 +74,39 @@ public long count() { } @Override - public List removeExpiredSchedules(DataProcessingContextModel dataProcessingContextModel) throws IOException { - //TODO move non mongo related logic to service - List deletedKraftwerkExecutionSchedules = new ArrayList<>(); - for (KraftwerkExecutionSchedule kraftwerkExecutionScheduleToRemove : - dataProcessingContextModel.getKraftwerkExecutionScheduleList().stream().filter( - kraftwerkExecutionSchedule -> kraftwerkExecutionSchedule.getScheduleEndDate().isBefore(LocalDateTime.now()) - ).toList()) { - deletedKraftwerkExecutionSchedules.add(kraftwerkExecutionScheduleToRemove); - Query query = - Query.query(Criteria.where("scheduleEndDate").is(kraftwerkExecutionScheduleToRemove.getScheduleEndDate())); - if (dataProcessingContextModel.getCollectionInstrumentId() != null){ - mongoTemplate.updateMulti(Query.query(Criteria.where("collectionInstrumentId").is(dataProcessingContextModel.getCollectionInstrumentId())), new Update().pull( - "kraftwerkExecutionScheduleList", query), - Constants.MONGODB_SCHEDULE_COLLECTION_NAME); - } + public List removeExpiredSchedules( + DataProcessingContextModel context + ) { + LocalDateTime now = LocalDateTime.now(); + + List deletedSchedules = + Optional.ofNullable(context.getKraftwerkExecutionScheduleV2List()) + .orElse(List.of()) + .stream() + .filter(schedule -> schedule.getScheduleEndDate() != null) + .filter(schedule -> schedule.getScheduleEndDate().isBefore(now)) + .toList(); + + for (KraftwerkExecutionScheduleV2 scheduleToRemove : deletedSchedules) { + Query query = Query.query( + Criteria.where("collectionInstrumentId").is(context.getCollectionInstrumentId()) + ); + + Update update = new Update().pull( + "kraftwerkExecutionScheduleV2List", + Query.query( + Criteria.where("scheduleUuid").is(scheduleToRemove.getScheduleUuid()) + ).getQueryObject() + ); + mongoTemplate.updateMulti( + query, + update, + Constants.MONGODB_CONTEXT_COLLECTION_NAME + ); + } - return deletedKraftwerkExecutionSchedules; + + return deletedSchedules; } @Override diff --git a/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java b/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java index 904a5ba1..021e8865 100644 --- a/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java +++ b/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java @@ -1,9 +1,12 @@ package fr.insee.genesis.infrastructure.adapter; import fr.insee.genesis.Constants; +import fr.insee.genesis.controller.utils.ExportType; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; +import fr.insee.genesis.domain.model.context.schedule.DestinationType; import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionSchedule; -import fr.insee.genesis.domain.model.context.schedule.ServiceToCall; +import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; +import fr.insee.genesis.domain.model.surveyunit.Mode; import fr.insee.genesis.infrastructure.document.context.DataProcessingContextDocument; import fr.insee.genesis.infrastructure.repository.DataProcessingContextMongoDBRepository; import org.junit.jupiter.api.DisplayName; @@ -21,6 +24,7 @@ import java.io.IOException; import java.time.LocalDateTime; import java.util.List; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -246,11 +250,11 @@ class RemoveExpiredSchedulesTests { @DisplayName("Should return empty list when no schedule is expired") void removeExpiredSchedules_noExpired_shouldReturnEmptyList() throws IOException { //GIVEN - KraftwerkExecutionSchedule future = buildSchedule(LocalDateTime.now().plusDays(1)); - DataProcessingContextModel model = buildModelWithSchedules(List.of(future)); + KraftwerkExecutionScheduleV2 future = buildSchedule(LocalDateTime.now().plusDays(1)); + DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(future)); //WHEN - List removed = adapter.removeExpiredSchedules(model); + List removed = adapter.removeExpiredSchedules(model); //THEN assertThat(removed).isEmpty(); @@ -261,11 +265,11 @@ void removeExpiredSchedules_noExpired_shouldReturnEmptyList() throws IOException @DisplayName("Should return expired schedules and call updateMulti by collectionInstrumentId when set") void removeExpiredSchedules_withCollectionInstrumentId_shouldUpdateByCollectionInstrumentId() throws IOException { //GIVEN - KraftwerkExecutionSchedule expired = buildSchedule(LocalDateTime.now().minusDays(1)); - DataProcessingContextModel model = buildModelWithSchedules(List.of(expired)); + KraftwerkExecutionScheduleV2 expired = buildSchedule(LocalDateTime.now().minusDays(1)); + DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(expired)); //WHEN - List removed = adapter.removeExpiredSchedules(model); + List removed = adapter.removeExpiredSchedules(model); //THEN assertThat(removed).hasSize(1).containsExactly(expired); @@ -274,7 +278,7 @@ void removeExpiredSchedules_withCollectionInstrumentId_shouldUpdateByCollectionI verify(mongoTemplate).updateMulti( queryCaptor.capture(), any(Update.class), - eq(Constants.MONGODB_SCHEDULE_COLLECTION_NAME) + eq(Constants.MONGODB_CONTEXT_COLLECTION_NAME) ); // The outer query must filter by collectionInstrumentId assertThat(queryCaptor.getValue().toString()).contains("collectionInstrumentId"); @@ -284,12 +288,12 @@ void removeExpiredSchedules_withCollectionInstrumentId_shouldUpdateByCollectionI @DisplayName("Should remove only expired schedules from a mixed list") void removeExpiredSchedules_mixedList_shouldRemoveOnlyExpired() throws IOException { //GIVEN - KraftwerkExecutionSchedule expired = buildSchedule(LocalDateTime.now().minusDays(1)); - KraftwerkExecutionSchedule future = buildSchedule(LocalDateTime.now().plusDays(1)); - DataProcessingContextModel model = buildModelWithSchedules(List.of(expired, future)); + KraftwerkExecutionScheduleV2 expired = buildSchedule(LocalDateTime.now().minusDays(1)); + KraftwerkExecutionScheduleV2 future = buildSchedule(LocalDateTime.now().plusDays(1)); + DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(expired, future)); //WHEN - List removed = adapter.removeExpiredSchedules(model); + List removed = adapter.removeExpiredSchedules(model); //THEN assertThat(removed).hasSize(1).containsExactly(expired); @@ -301,12 +305,12 @@ void removeExpiredSchedules_mixedList_shouldRemoveOnlyExpired() throws IOExcepti @DisplayName("Should call updateMulti once per expired schedule") void removeExpiredSchedules_multipleExpired_shouldCallUpdateMultiForEach() throws IOException { //GIVEN - KraftwerkExecutionSchedule expired1 = buildSchedule(LocalDateTime.now().minusDays(1)); - KraftwerkExecutionSchedule expired2 = buildSchedule(LocalDateTime.now().minusDays(2)); - DataProcessingContextModel model = buildModelWithSchedules(List.of(expired1, expired2)); + KraftwerkExecutionScheduleV2 expired1 = buildSchedule(LocalDateTime.now().minusDays(1)); + KraftwerkExecutionScheduleV2 expired2 = buildSchedule(LocalDateTime.now().minusDays(2)); + DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(expired1, expired2)); //WHEN - List removed = adapter.removeExpiredSchedules(model); + List removed = adapter.removeExpiredSchedules(model); //THEN assertThat(removed).hasSize(2); @@ -320,7 +324,7 @@ void removeExpiredSchedules_emptyScheduleList_shouldReturnEmptyList() throws IOE DataProcessingContextModel model = buildModelWithSchedules(List.of()); //WHEN - List removed = adapter.removeExpiredSchedules(model); + List removed = adapter.removeExpiredSchedules(model); //THEN assertThat(removed).isEmpty(); @@ -403,15 +407,20 @@ void findAllByReview_emptyRepository_shouldReturnEmptyList() { } //UTILS - private KraftwerkExecutionSchedule buildSchedule(LocalDateTime endDate) { - return new KraftwerkExecutionSchedule( - null, + private KraftwerkExecutionScheduleV2 buildSchedule(LocalDateTime endDate) { + return new KraftwerkExecutionScheduleV2( + UUID.randomUUID().toString(), "0 10 * * *", - ServiceToCall.GENESIS, + ExportType.JSON, LocalDateTime.now(), endDate, - null - ); + Mode.WEB, + DestinationType.APPLISHARE, + false, + "string", + false, + null, + 100); } private DataProcessingContextModel buildModelWithSchedules(List schedules) { @@ -421,6 +430,15 @@ private DataProcessingContextModel buildModelWithSchedules(List schedules + ) { + return DataProcessingContextModel.builder() + .collectionInstrumentId(DataProcessingContextMongoAdapterTest.COLLECTION_INSTRUMENT_ID) + .kraftwerkExecutionScheduleV2List(schedules) + .build(); + } + private DataProcessingContextDocument buildDocWithReview(boolean withReview) { DataProcessingContextDocument doc = new DataProcessingContextDocument(); doc.setWithReview(withReview); From b77b718fe09ec6477b91e141e885df96e962b13d Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Mon, 18 May 2026 16:38:51 +0200 Subject: [PATCH 2/3] update delete logic to delete v1 and V2 schedules --- .../schedule/DeletedExpiredSchedules.java | 12 ++ .../DataProcessingContextPersistancePort.java | 3 +- .../context/DataProcessingContextService.java | 8 +- .../DataProcessingContextMongoAdapter.java | 45 ++++++-- ...DataProcessingContextMongoAdapterTest.java | 104 +++++++++--------- 5 files changed, 105 insertions(+), 67 deletions(-) create mode 100644 src/main/java/fr/insee/genesis/domain/model/context/schedule/DeletedExpiredSchedules.java diff --git a/src/main/java/fr/insee/genesis/domain/model/context/schedule/DeletedExpiredSchedules.java b/src/main/java/fr/insee/genesis/domain/model/context/schedule/DeletedExpiredSchedules.java new file mode 100644 index 00000000..d0f7fde9 --- /dev/null +++ b/src/main/java/fr/insee/genesis/domain/model/context/schedule/DeletedExpiredSchedules.java @@ -0,0 +1,12 @@ +package fr.insee.genesis.domain.model.context.schedule; + +import java.util.List; + +public record DeletedExpiredSchedules( + List v1Schedules, + List v2Schedules +) { + public boolean isEmpty() { + return v1Schedules.isEmpty() && v2Schedules.isEmpty(); + } +} diff --git a/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java b/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java index 8ebfb0b6..182c92b9 100644 --- a/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java +++ b/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java @@ -1,6 +1,7 @@ package fr.insee.genesis.domain.ports.spi; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; +import fr.insee.genesis.domain.model.context.schedule.DeletedExpiredSchedules; import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; import fr.insee.genesis.infrastructure.document.context.DataProcessingContextDocument; @@ -21,7 +22,7 @@ public interface DataProcessingContextPersistancePort { long count(); - List removeExpiredSchedules(DataProcessingContextModel dataProcessingContextModel) throws IOException; + DeletedExpiredSchedules removeExpiredSchedules(DataProcessingContextModel dataProcessingContextModel) throws IOException; List findAllByReview(boolean withReview); } diff --git a/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java b/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java index eaf0cf69..d257bf97 100644 --- a/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java +++ b/src/main/java/fr/insee/genesis/domain/service/context/DataProcessingContextService.java @@ -6,6 +6,7 @@ import fr.insee.genesis.controller.dto.KraftwerkExecutionScheduleInput; import fr.insee.genesis.controller.dto.rawdata.ScheduleResponseDto; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; +import fr.insee.genesis.domain.model.context.schedule.DeletedExpiredSchedules; import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; import fr.insee.genesis.domain.model.surveyunit.SurveyUnitModel; import fr.insee.genesis.domain.ports.api.DataProcessingContextApiPort; @@ -271,11 +272,10 @@ public void deleteExpiredSchedules(String logFolder) throws GenesisException { for (DataProcessingContextModel context : dataProcessingContextModels) { try { - List deletedKraftwerkExecutionSchedules = + DeletedExpiredSchedules deletedSchedules = dataProcessingContextPersistancePort.removeExpiredSchedules(context); - // Save in JSON log - if (!deletedKraftwerkExecutionSchedules.isEmpty()) { + if (!deletedSchedules.isEmpty()) { String scheduleName = context.getCollectionInstrumentId(); Path jsonLogPath = Path.of( logFolder, @@ -286,7 +286,7 @@ public void deleteExpiredSchedules(String logFolder) throws GenesisException { ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); objectMapper.registerModule(new JavaTimeModule()); - String jsonToWrite = objectMapper.writeValueAsString(deletedKraftwerkExecutionSchedules); + String jsonToWrite = objectMapper.writeValueAsString(deletedSchedules); if (Files.exists(jsonLogPath)) { StringBuilder content = new StringBuilder(Files.readString(jsonLogPath)); diff --git a/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java b/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java index 3b277992..f556b085 100644 --- a/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java +++ b/src/main/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapter.java @@ -2,6 +2,8 @@ import fr.insee.genesis.Constants; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; +import fr.insee.genesis.domain.model.context.schedule.DeletedExpiredSchedules; +import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; import fr.insee.genesis.domain.ports.spi.DataProcessingContextPersistancePort; import fr.insee.genesis.infrastructure.document.context.DataProcessingContextDocument; @@ -74,12 +76,18 @@ public long count() { } @Override - public List removeExpiredSchedules( - DataProcessingContextModel context - ) { + public DeletedExpiredSchedules removeExpiredSchedules(DataProcessingContextModel context) { LocalDateTime now = LocalDateTime.now(); - List deletedSchedules = + List deletedV1 = + Optional.ofNullable(context.getKraftwerkExecutionScheduleList()) + .orElse(List.of()) + .stream() + .filter(schedule -> schedule.getScheduleEndDate() != null) + .filter(schedule -> schedule.getScheduleEndDate().isBefore(now)) + .toList(); + + List deletedV2 = Optional.ofNullable(context.getKraftwerkExecutionScheduleV2List()) .orElse(List.of()) .stream() @@ -87,26 +95,43 @@ public List removeExpiredSchedules( .filter(schedule -> schedule.getScheduleEndDate().isBefore(now)) .toList(); - for (KraftwerkExecutionScheduleV2 scheduleToRemove : deletedSchedules) { - Query query = Query.query( - Criteria.where("collectionInstrumentId").is(context.getCollectionInstrumentId()) + Query query = Query.query( + Criteria.where("collectionInstrumentId").is(context.getCollectionInstrumentId()) + ); + + for (KraftwerkExecutionSchedule scheduleToRemove : deletedV1) { + Update update = new Update().pull( + "kraftwerkExecutionScheduleList", + Query.query( + Criteria.where("scheduleEndDate") + .is(scheduleToRemove.getScheduleEndDate()) + ).getQueryObject() + ); + + mongoTemplate.updateMulti( + query, + update, + Constants.MONGODB_CONTEXT_COLLECTION_NAME ); + } + for (KraftwerkExecutionScheduleV2 scheduleToRemove : deletedV2) { Update update = new Update().pull( "kraftwerkExecutionScheduleV2List", Query.query( - Criteria.where("scheduleUuid").is(scheduleToRemove.getScheduleUuid()) + Criteria.where("scheduleUuid") + .is(scheduleToRemove.getScheduleUuid()) ).getQueryObject() ); + mongoTemplate.updateMulti( query, update, Constants.MONGODB_CONTEXT_COLLECTION_NAME ); - } - return deletedSchedules; + return new DeletedExpiredSchedules(deletedV1, deletedV2); } @Override diff --git a/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java b/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java index 021e8865..7920beec 100644 --- a/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java +++ b/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java @@ -3,6 +3,7 @@ import fr.insee.genesis.Constants; import fr.insee.genesis.controller.utils.ExportType; import fr.insee.genesis.domain.model.context.DataProcessingContextModel; +import fr.insee.genesis.domain.model.context.schedule.DeletedExpiredSchedules; import fr.insee.genesis.domain.model.context.schedule.DestinationType; import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionSchedule; import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; @@ -21,7 +22,6 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; -import java.io.IOException; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; @@ -241,93 +241,92 @@ void count_empty_shouldReturnZero() { assertThat(adapter.count()).isZero(); } } - @Nested @DisplayName("removeExpiredSchedules() tests") class RemoveExpiredSchedulesTests { @Test - @DisplayName("Should return empty list when no schedule is expired") - void removeExpiredSchedules_noExpired_shouldReturnEmptyList() throws IOException { - //GIVEN - KraftwerkExecutionScheduleV2 future = buildSchedule(LocalDateTime.now().plusDays(1)); + @DisplayName("Should return empty result when no schedule is expired") + void removeExpiredSchedules_noExpired_shouldReturnEmptyResult() { + KraftwerkExecutionScheduleV2 future = buildScheduleV2(LocalDateTime.now().plusDays(1)); DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(future)); - //WHEN - List removed = adapter.removeExpiredSchedules(model); + DeletedExpiredSchedules removed = adapter.removeExpiredSchedules(model); - //THEN - assertThat(removed).isEmpty(); + assertThat(removed.isEmpty()).isTrue(); + assertThat(removed.v1Schedules()).isEmpty(); + assertThat(removed.v2Schedules()).isEmpty(); verifyNoInteractions(mongoTemplate); } @Test - @DisplayName("Should return expired schedules and call updateMulti by collectionInstrumentId when set") - void removeExpiredSchedules_withCollectionInstrumentId_shouldUpdateByCollectionInstrumentId() throws IOException { - //GIVEN - KraftwerkExecutionScheduleV2 expired = buildSchedule(LocalDateTime.now().minusDays(1)); + @DisplayName("Should return expired V2 schedules and call updateMulti") + void removeExpiredSchedules_withExpiredV2_shouldUpdateByCollectionInstrumentId() { + KraftwerkExecutionScheduleV2 expired = buildScheduleV2(LocalDateTime.now().minusDays(1)); DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(expired)); - //WHEN - List removed = adapter.removeExpiredSchedules(model); + DeletedExpiredSchedules removed = adapter.removeExpiredSchedules(model); - //THEN - assertThat(removed).hasSize(1).containsExactly(expired); + assertThat(removed.v1Schedules()).isEmpty(); + assertThat(removed.v2Schedules()).hasSize(1).containsExactly(expired); ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(Query.class); + verify(mongoTemplate).updateMulti( queryCaptor.capture(), any(Update.class), eq(Constants.MONGODB_CONTEXT_COLLECTION_NAME) ); - // The outer query must filter by collectionInstrumentId + assertThat(queryCaptor.getValue().toString()).contains("collectionInstrumentId"); } @Test - @DisplayName("Should remove only expired schedules from a mixed list") - void removeExpiredSchedules_mixedList_shouldRemoveOnlyExpired() throws IOException { - //GIVEN - KraftwerkExecutionScheduleV2 expired = buildSchedule(LocalDateTime.now().minusDays(1)); - KraftwerkExecutionScheduleV2 future = buildSchedule(LocalDateTime.now().plusDays(1)); + @DisplayName("Should remove only expired V2 schedules from a mixed V2 list") + void removeExpiredSchedules_mixedV2List_shouldRemoveOnlyExpired() { + KraftwerkExecutionScheduleV2 expired = buildScheduleV2(LocalDateTime.now().minusDays(1)); + KraftwerkExecutionScheduleV2 future = buildScheduleV2(LocalDateTime.now().plusDays(1)); DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(expired, future)); - //WHEN - List removed = adapter.removeExpiredSchedules(model); + DeletedExpiredSchedules removed = adapter.removeExpiredSchedules(model); - //THEN - assertThat(removed).hasSize(1).containsExactly(expired); - // updateMulti called once, only for the expired one - verify(mongoTemplate, times(1)).updateMulti(any(), any(), any(String.class)); + assertThat(removed.v1Schedules()).isEmpty(); + assertThat(removed.v2Schedules()).hasSize(1).containsExactly(expired); + + verify(mongoTemplate, times(1)) + .updateMulti(any(), any(), eq(Constants.MONGODB_CONTEXT_COLLECTION_NAME)); } @Test - @DisplayName("Should call updateMulti once per expired schedule") - void removeExpiredSchedules_multipleExpired_shouldCallUpdateMultiForEach() throws IOException { - //GIVEN - KraftwerkExecutionScheduleV2 expired1 = buildSchedule(LocalDateTime.now().minusDays(1)); - KraftwerkExecutionScheduleV2 expired2 = buildSchedule(LocalDateTime.now().minusDays(2)); + @DisplayName("Should call updateMulti once per expired V2 schedule") + void removeExpiredSchedules_multipleExpiredV2_shouldCallUpdateMultiForEach() { + KraftwerkExecutionScheduleV2 expired1 = buildScheduleV2(LocalDateTime.now().minusDays(1)); + KraftwerkExecutionScheduleV2 expired2 = buildScheduleV2(LocalDateTime.now().minusDays(2)); DataProcessingContextModel model = buildModelWithSchedulesV2(List.of(expired1, expired2)); - //WHEN - List removed = adapter.removeExpiredSchedules(model); + DeletedExpiredSchedules removed = adapter.removeExpiredSchedules(model); - //THEN - assertThat(removed).hasSize(2); - verify(mongoTemplate, times(2)).updateMulti(any(), any(), any(String.class)); + assertThat(removed.v1Schedules()).isEmpty(); + assertThat(removed.v2Schedules()).hasSize(2); + + verify(mongoTemplate, times(2)) + .updateMulti(any(), any(), eq(Constants.MONGODB_CONTEXT_COLLECTION_NAME)); } @Test - @DisplayName("Should return empty list when schedule list is empty") - void removeExpiredSchedules_emptyScheduleList_shouldReturnEmptyList() throws IOException { - //GIVEN - DataProcessingContextModel model = buildModelWithSchedules(List.of()); - - //WHEN - List removed = adapter.removeExpiredSchedules(model); - - //THEN - assertThat(removed).isEmpty(); + @DisplayName("Should return empty result when schedule lists are empty") + void removeExpiredSchedules_emptyScheduleLists_shouldReturnEmptyResult() { + DataProcessingContextModel model = DataProcessingContextModel.builder() + .collectionInstrumentId(DataProcessingContextMongoAdapterTest.COLLECTION_INSTRUMENT_ID) + .kraftwerkExecutionScheduleList(List.of()) + .kraftwerkExecutionScheduleV2List(List.of()) + .build(); + + DeletedExpiredSchedules removed = adapter.removeExpiredSchedules(model); + + assertThat(removed.isEmpty()).isTrue(); + assertThat(removed.v1Schedules()).isEmpty(); + assertThat(removed.v2Schedules()).isEmpty(); verifyNoInteractions(mongoTemplate); } } @@ -407,7 +406,7 @@ void findAllByReview_emptyRepository_shouldReturnEmptyList() { } //UTILS - private KraftwerkExecutionScheduleV2 buildSchedule(LocalDateTime endDate) { + private KraftwerkExecutionScheduleV2 buildScheduleV2(LocalDateTime endDate) { return new KraftwerkExecutionScheduleV2( UUID.randomUUID().toString(), "0 10 * * *", @@ -420,7 +419,8 @@ private KraftwerkExecutionScheduleV2 buildSchedule(LocalDateTime endDate) { "string", false, null, - 100); + 100 + ); } private DataProcessingContextModel buildModelWithSchedules(List schedules) { From 5203cc618f9e53fac2c1349bc8a33891617970bf Mon Sep 17 00:00:00 2001 From: Hajarel-moukh Date: Mon, 18 May 2026 16:52:11 +0200 Subject: [PATCH 3/3] delete unused import and method --- .../ports/spi/DataProcessingContextPersistancePort.java | 1 - .../adapter/DataProcessingContextMongoAdapterTest.java | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java b/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java index 182c92b9..b3d77514 100644 --- a/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java +++ b/src/main/java/fr/insee/genesis/domain/ports/spi/DataProcessingContextPersistancePort.java @@ -2,7 +2,6 @@ import fr.insee.genesis.domain.model.context.DataProcessingContextModel; import fr.insee.genesis.domain.model.context.schedule.DeletedExpiredSchedules; -import fr.insee.genesis.domain.model.context.schedule.KraftwerkExecutionScheduleV2; import fr.insee.genesis.infrastructure.document.context.DataProcessingContextDocument; import java.io.IOException; diff --git a/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java b/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java index 7920beec..0414e025 100644 --- a/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java +++ b/src/test/java/fr/insee/genesis/infrastructure/adapter/DataProcessingContextMongoAdapterTest.java @@ -423,13 +423,6 @@ private KraftwerkExecutionScheduleV2 buildScheduleV2(LocalDateTime endDate) { ); } - private DataProcessingContextModel buildModelWithSchedules(List schedules) { - return DataProcessingContextModel.builder() - .collectionInstrumentId(DataProcessingContextMongoAdapterTest.COLLECTION_INSTRUMENT_ID) - .kraftwerkExecutionScheduleList(schedules) - .build(); - } - private DataProcessingContextModel buildModelWithSchedulesV2( List schedules ) {