From e15e95cb2ad7816b14c5b033d047247d812cf0b8 Mon Sep 17 00:00:00 2001 From: empassaro <113031808+empassaro@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:17:59 +0200 Subject: [PATCH] [SELC-5324] feat: added control to send two types of notifications (#424) --- ...tificationEventResenderServiceDefault.java | 73 ++++++++- .../NotificationEventServiceDefault.java | 9 +- .../onboarding/service/OnboardingService.java | 47 ++++-- .../onboarding/utils/CustomMetricsConst.java | 11 ++ ...cationEventResenderServiceDefaultTest.java | 146 +++++++++++++++--- 5 files changed, 241 insertions(+), 45 deletions(-) create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefault.java index 3e7d65834..a173a44d1 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefault.java @@ -1,26 +1,50 @@ package it.pagopa.selfcare.onboarding.service; +import com.microsoft.applicationinsights.TelemetryClient; +import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.azure.functions.ExecutionContext; import io.quarkus.runtime.util.ExceptionUtil; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.dto.QueueEvent; import it.pagopa.selfcare.onboarding.dto.ResendNotificationsFilters; import it.pagopa.selfcare.onboarding.entity.Onboarding; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.core.Context; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; +import static it.pagopa.selfcare.onboarding.utils.CustomMetricsConst.EVENT_ONBOARDING_FN_NAME; +import static it.pagopa.selfcare.onboarding.utils.CustomMetricsConst.EVENT_ONBOARDING_INSTTITUTION_FN_FAILURE; + @ApplicationScoped public class NotificationEventResenderServiceDefault implements NotificationEventResenderService { private final NotificationEventService notificationEventService; private final OnboardingService onboardingService; - + private final TelemetryClient telemetryClient; + public static final String OPERATION_NAME = "ONBOARDING-FN"; private static final String RESEND_ENDING_LOG = "Resend notifications for page %s completed"; private static final String RESEND_ENDING_LOG_LAST_PAGE = "There aren't more notifications to resend, page %s completed"; - public NotificationEventResenderServiceDefault(NotificationEventService notificationEventService, OnboardingService onboardingService) { + public NotificationEventResenderServiceDefault( + NotificationEventService notificationEventService, + OnboardingService onboardingService, + @Context @ConfigProperty(name = "onboarding-functions.appinsights.connection-string") String appInsightsConnectionString + ) { this.notificationEventService = notificationEventService; this.onboardingService = onboardingService; + TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.createDefault(); + telemetryConfiguration.setConnectionString(appInsightsConnectionString); + this.telemetryClient = new TelemetryClient(telemetryConfiguration); + this.telemetryClient.getContext().getOperation().setName(OPERATION_NAME); } public ResendNotificationsFilters resendNotifications(ResendNotificationsFilters filters, ExecutionContext context) { @@ -33,9 +57,17 @@ public ResendNotificationsFilters resendNotifications(ResendNotificationsFilters context.getLogger().info(() -> String.format("Found: %s onboardings to send for page: %s ", onboardingsToResend.size(), page)); for (Onboarding onboarding : onboardingsToResend) { try { - notificationEventService.send(context, onboarding, null, filters.getNotificationEventTraceId()); + if(onboardingHasBeenDeletedInRange(onboarding, filters.getFrom(), filters.getTo())) { + notificationEventService.send(context, onboarding, QueueEvent.UPDATE, filters.getNotificationEventTraceId()); + } + + if(onboardingHasBeenActivatedInRange(onboarding, filters.getFrom(), filters.getTo())) { + onboarding.setStatus(OnboardingStatus.COMPLETED); + notificationEventService.send(context, onboarding, QueueEvent.ADD, filters.getNotificationEventTraceId()); + } } catch (Exception e) { context.getLogger().severe(() -> String.format("ERROR: Sending onboarding %s error: %s ", onboarding.getId(), ExceptionUtil.generateStackTrace(e))); + trackErrorEvent(onboarding, e, filters.getNotificationEventTraceId()); } } @@ -49,4 +81,39 @@ public ResendNotificationsFilters resendNotifications(ResendNotificationsFilters filters.setPage(page + 1); return filters; } + + private boolean onboardingHasBeenDeletedInRange(Onboarding onboarding, String from, String to) { + if(onboarding.getStatus() != OnboardingStatus.DELETED) { + return false; + } + + return doesDateFallInRange(onboarding.getDeletedAt(), from, to); + } + + private boolean onboardingHasBeenActivatedInRange(Onboarding onboarding, String from, String to) { + return doesDateFallInRange(onboarding.getActivatedAt(), from, to); + } + + private static boolean doesDateFallInRange(LocalDateTime date, String from, String to) { + if(date == null) { + return false; + } + + LocalDate fromDate = StringUtils.isNotBlank(from) ? LocalDate.parse(from, DateTimeFormatter.ISO_LOCAL_DATE) : null; + LocalDate toDate = StringUtils.isNotBlank(to) ? LocalDate.parse(to, DateTimeFormatter.ISO_LOCAL_DATE) : null; + return (fromDate == null || date.isEqual(fromDate.atStartOfDay()) || date.isAfter(fromDate.atStartOfDay())) && + (toDate == null || date.isEqual(toDate.atStartOfDay()) || date.isBefore(toDate.plusDays(1).atStartOfDay())); + } + + private void trackErrorEvent(Onboarding onboarding, Exception e, String notificationEventTraceId) { + telemetryClient.trackEvent(EVENT_ONBOARDING_FN_NAME, onboardingEventFailureMap(onboarding, e, notificationEventTraceId), Map.of(EVENT_ONBOARDING_INSTTITUTION_FN_FAILURE, 1D)); + } + + private static Map onboardingEventFailureMap(Onboarding onboarding, Exception e, String notificationEventTraceId) { + Map propertiesMap = new HashMap<>(); + Optional.ofNullable(onboarding.getId()).ifPresent(value -> propertiesMap.put("id", value)); + Optional.ofNullable(notificationEventTraceId).ifPresent(value -> propertiesMap.put("notificationEventTraceId", value)); + Optional.ofNullable(e).ifPresent(value -> propertiesMap.put("error", ExceptionUtil.generateStackTrace(e))); + return propertiesMap; + } } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java index d1d6f6547..e6727ae16 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java @@ -31,15 +31,12 @@ import java.util.*; +import static it.pagopa.selfcare.onboarding.utils.CustomMetricsConst.EVENT_ONBOARDING_FN_NAME; +import static it.pagopa.selfcare.onboarding.utils.CustomMetricsConst.EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS; import static it.pagopa.selfcare.onboarding.utils.Utils.isNotInstitutionOnboarding; @ApplicationScoped public class NotificationEventServiceDefault implements NotificationEventService { - - public static final String EVENT_ONBOARDING_FN_NAME = "ONBOARDING-FN"; - public static final String EVENT_ONBOARDING_INSTTITUTION_FN_FAILURE = "EventsOnboardingInstitution_failures"; - public static final String EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS = "EventsOnboardingInstitution_success"; - public static final String OPERATION_NAME = "ONBOARDING-FN"; private final TelemetryClient telemetryClient; @RestClient @Inject @@ -70,7 +67,7 @@ public NotificationEventServiceDefault(ProductService productService, TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.createDefault(); telemetryConfiguration.setConnectionString(appInsightsConnectionString); this.telemetryClient = new TelemetryClient(telemetryConfiguration); - this.telemetryClient.getContext().getOperation().setName(OPERATION_NAME); + this.telemetryClient.getContext().getOperation().setName(EVENT_ONBOARDING_FN_NAME); mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java index f6e9fb46a..9d61bdee6 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java @@ -40,7 +40,8 @@ import java.util.Optional; import java.util.stream.Collectors; -import static it.pagopa.selfcare.onboarding.utils.Utils.CONTRACT_FILENAME_FUNC; +import static it.pagopa.selfcare.onboarding.utils.Utils.*; +import java.util.stream.Stream; import static it.pagopa.selfcare.onboarding.utils.Utils.NOT_ALLOWED_WORKFLOWS_FOR_INSTITUTION_NOTIFICATIONS; @ApplicationScoped @@ -52,7 +53,6 @@ public class OnboardingService { public static final String USER_REQUEST_DOES_NOT_FOUND = "User request does not found for onboarding %s"; public static final String ACTIVATED_AT_FIELD = "activatedAt"; public static final String DELETED_AT_FIELD = "deletedAt"; - public static final String CREATED_AT = "createdAt"; private static final String WORKFLOW_TYPE = "workflowType"; @RestClient @@ -259,7 +259,8 @@ public List countNotifications(String productId, String } - public NotificationCountResult countNotificationsByFilters(String productId, String from, String to, ExecutionContext context) {Document queryAddEvent = getQueryNotificationAdd(productId, from, to); + public NotificationCountResult countNotificationsByFilters(String productId, String from, String to, ExecutionContext context) { + Document queryAddEvent = getQueryNotificationAdd(productId, from, to); Document queryUpdateEvent = getQueryNotificationDelete(productId, from, to); long countAddEvents = repository.find(queryAddEvent).count(); @@ -289,7 +290,7 @@ private Document createQuery(String productId, List status, St } Document dateQuery = new Document(); Optional.ofNullable(from).ifPresent(value -> query.append(dateField, dateQuery.append("$gte", LocalDate.parse(from, DateTimeFormatter.ISO_LOCAL_DATE)))); - Optional.ofNullable(to).ifPresent(value -> query.append(dateField, dateQuery.append("$lte", LocalDate.parse(to, DateTimeFormatter.ISO_LOCAL_DATE)))); + Optional.ofNullable(to).ifPresent(value -> query.append(dateField, dateQuery.append("$lte", LocalDate.parse(to, DateTimeFormatter.ISO_LOCAL_DATE).plusDays(1)))); if(!dateQuery.isEmpty()) { query.append(dateField, dateQuery); } @@ -317,20 +318,38 @@ private Document createQueryByFilters(ResendNotificationsFilters filters) { Optional.ofNullable(filters.getTaxCode()).ifPresent(value -> query.append("institution.taxCode", value)); query.append("status", new Document("$in", filters.getStatus())); - Document dateQuery = new Document(); - Optional.ofNullable(filters.getFrom()).ifPresent(value -> query.append(CREATED_AT, dateQuery.append("$gte", LocalDate.parse(filters.getFrom(), DateTimeFormatter.ISO_LOCAL_DATE)))); - Optional.ofNullable(filters.getTo()).ifPresent(value -> query.append(CREATED_AT, dateQuery.append("$lte", LocalDate.parse(filters.getTo(), DateTimeFormatter.ISO_LOCAL_DATE)))); - if(!dateQuery.isEmpty()) { - query.append(CREATED_AT, dateQuery); - } + List dateQueries = createDateQueries(filters); + List workflowCriteria = createWorkflowCriteria(); + + query.append("$and", List.of( + new Document("$or", dateQueries), + new Document("$or", workflowCriteria) + )); - List workflowCriteria = new ArrayList<>(); - workflowCriteria.add(new Document(WORKFLOW_TYPE, new Document("$nin", NOT_ALLOWED_WORKFLOWS_FOR_INSTITUTION_NOTIFICATIONS.stream().map(Enum::name).toList()))); - workflowCriteria.add(new Document(WORKFLOW_TYPE, new Document("$exists", false))); - query.append("$or", workflowCriteria); return query; } + private List createDateQueries(ResendNotificationsFilters filters) { + return Stream.of( + createIntervalQueryForDate(filters, ACTIVATED_AT_FIELD), + createIntervalQueryForDate(filters, DELETED_AT_FIELD) + ).filter(doc -> !doc.isEmpty()).toList(); + } + + private Document createIntervalQueryForDate(ResendNotificationsFilters filters, String dateField) { + Document dateQuery = new Document(); + Optional.ofNullable(filters.getFrom()).ifPresent(value -> dateQuery.append("$gte", LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE))); + Optional.ofNullable(filters.getTo()).ifPresent(value -> dateQuery.append("$lte", LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE).plusDays(1))); + return new Document(dateField, dateQuery); + } + + private List createWorkflowCriteria() { + return List.of( + new Document(WORKFLOW_TYPE, new Document("$nin", NOT_ALLOWED_WORKFLOWS_FOR_INSTITUTION_NOTIFICATIONS.stream().map(Enum::name).toList())), + new Document(WORKFLOW_TYPE, new Document("$exists", false)) + ); + } + static class SendMailInput { Product product; String userRequestName; diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java new file mode 100644 index 000000000..270082f3a --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java @@ -0,0 +1,11 @@ +package it.pagopa.selfcare.onboarding.utils; + +public class CustomMetricsConst { + private CustomMetricsConst() { + } + + public static final String EVENT_ONBOARDING_FN_NAME = "ONBOARDING-FN"; + public static final String EVENT_ONBOARDING_INSTTITUTION_FN_FAILURE = "EventsOnboardingInstitution_failures"; + public static final String EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS = "EventsOnboardingInstitution_success"; + +} diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java index e6b4f1b7b..bdb5fe1a8 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java @@ -3,15 +3,17 @@ import com.microsoft.azure.functions.ExecutionContext; import io.quarkus.test.InjectMock; import io.quarkus.test.junit.QuarkusTest; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.dto.QueueEvent; import it.pagopa.selfcare.onboarding.dto.ResendNotificationsFilters; import it.pagopa.selfcare.onboarding.entity.Onboarding; import it.pagopa.selfcare.onboarding.exception.NotificationException; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import java.util.logging.Logger; import static it.pagopa.selfcare.onboarding.TestUtils.getMockedContext; import static org.junit.jupiter.api.Assertions.*; @@ -30,13 +32,110 @@ class NotificationEventResenderServiceDefaultTest { OnboardingService onboardingService; @Test - void resendNotificationsEndsWithNullIfIsWorkingOnLastPage() { + void resendNotifications_withDoubleOnboardingAndThreeEventsExpected() { + /* Test that the resendNotifications method works correctly when there are two onboardings 1 COMPLETED (which should produce one notification) and 1 DELETED (which should produce two notifications) and no range is specified */ // Arrange ResendNotificationsFilters filters = ResendNotificationsFilters.builder().onboardingId("test").build(); ExecutionContext context = getMockedContext(); - when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(mockOnboardingList(2)); - doNothing().when(notificationEventService).send(any(), any(), any()); + Onboarding onboarding = new Onboarding(); + onboarding.setId("id1"); + onboarding.setStatus(OnboardingStatus.COMPLETED); + onboarding.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + Onboarding onboarding2 = new Onboarding(); + onboarding2.setId("id2"); + onboarding2.setStatus(OnboardingStatus.DELETED); + onboarding2.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + onboarding2.setDeletedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + + + when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(List.of(onboarding, onboarding2)); + doNothing().when(notificationEventService).send(any(), any(), any(), any()); + + // Act + ResendNotificationsFilters resendNotificationsFilters = notificationEventResenderServiceDefault.resendNotifications(filters, context); + + // Assert + verify(notificationEventService, times(3)).send(any(), any(), any(), any()); + verify(onboardingService).getOnboardingsToResend(filters, 0, 100); + assertNull(resendNotificationsFilters); + } + + @Test + void resendNotifications_withDoubleOnboardingAndTwoEventsExpected() { + /* Test that the resendNotifications method works correctly when there are two onboardings in status COMPLETED (which should produce one notification) and no range is specified */ + // Arrange + ResendNotificationsFilters filters = ResendNotificationsFilters.builder().onboardingId("test").build(); + ExecutionContext context = getMockedContext(); + + Onboarding onboarding = new Onboarding(); + onboarding.setId("id1"); + onboarding.setStatus(OnboardingStatus.COMPLETED); + onboarding.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + Onboarding onboarding2 = new Onboarding(); + onboarding2.setId("id2"); + onboarding2.setStatus(OnboardingStatus.COMPLETED); + onboarding2.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + + + when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(List.of(onboarding, onboarding2)); + doNothing().when(notificationEventService).send(any(), any(), any(), any()); + + // Act + ResendNotificationsFilters resendNotificationsFilters = notificationEventResenderServiceDefault.resendNotifications(filters, context); + + // Assert + verify(notificationEventService, times(2)).send(any(), any(), any(), any()); + verify(onboardingService).getOnboardingsToResend(filters, 0, 100); + assertNull(resendNotificationsFilters); + } + + @Test + void resendNotifications_withOneOnboardingAndTwoEventsExpected() { + /* Test that the resendNotifications method works correctly when there is 1 onboarding in status DELETED (which should produce two notification) and both activatedAt and deletedAt dates fall in specified range */ + // Arrange + ResendNotificationsFilters filters = ResendNotificationsFilters.builder() + .onboardingId("test") + .from("2023-02-01") + .build(); + ExecutionContext context = getMockedContext(); + + Onboarding onboarding = new Onboarding(); + onboarding.setId("id1"); + onboarding.setStatus(OnboardingStatus.DELETED); + onboarding.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + onboarding.setDeletedAt(LocalDateTime.of(2023, 2, 3, 0, 0)); + + + when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(List.of(onboarding)); + doNothing().when(notificationEventService).send(any(), any(), any(), any()); + + // Act + ResendNotificationsFilters resendNotificationsFilters = notificationEventResenderServiceDefault.resendNotifications(filters, context); + + // Assert + verify(notificationEventService, times(2)).send(any(), any(), any(), any()); + verify(onboardingService).getOnboardingsToResend(filters, 0, 100); + assertNull(resendNotificationsFilters); + } + + @Test + void resendNotificationsDoesntStopWhenSendProcessFails() { + // Arrange + ResendNotificationsFilters filters = new ResendNotificationsFilters(); + ExecutionContext context = getMockedContext(); + + Onboarding onboarding = new Onboarding(); + onboarding.setId("id1"); + onboarding.setStatus(OnboardingStatus.COMPLETED); + onboarding.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + Onboarding onboarding2 = new Onboarding(); + onboarding2.setId("id2"); + onboarding2.setStatus(OnboardingStatus.COMPLETED); + onboarding2.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + + doThrow(new NotificationException("Error")).when(notificationEventService).send(context, onboarding, QueueEvent.ADD, null); + when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(List.of(onboarding, onboarding2)); // Act ResendNotificationsFilters resendNotificationsFilters = notificationEventResenderServiceDefault.resendNotifications(filters, context); @@ -53,8 +152,8 @@ void resendNotificationsEndsIncrementingPageIfIsWorkingOnIntermediatePage() { ResendNotificationsFilters filters = ResendNotificationsFilters.builder().onboardingId("test").build(); ExecutionContext context = getMockedContext(); - when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(mockOnboardingList(100)); - doNothing().when(notificationEventService).send(any(), any(), any()); + when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(getMockedList(100)); + doNothing().when(notificationEventService).send(any(), any(), any(), any()); // Act ResendNotificationsFilters resendNotificationsFilters = notificationEventResenderServiceDefault.resendNotifications(filters, context); @@ -67,31 +166,34 @@ void resendNotificationsEndsIncrementingPageIfIsWorkingOnIntermediatePage() { } @Test - void resendNotificationsActivityException() { - ExecutionContext context = mock(ExecutionContext.class); - doReturn(Logger.getGlobal()).when(context).getLogger(); - - doThrow(new NotificationException("Error")).when(notificationEventService).send(any(), any(), any(), any()); - - List onboardings = new ArrayList<>(); - onboardings.add(new Onboarding()); - when(onboardingService.getOnboardingsToResend(any(), anyInt(), anyInt())).thenReturn(onboardings); + void resendNotificationsEndsWithMoreElementsToRetrieve() { + // Arrange + ResendNotificationsFilters filters = new ResendNotificationsFilters(); + ExecutionContext context = getMockedContext(); - ResendNotificationsFilters resendNotificationsFilters = new ResendNotificationsFilters(); - resendNotificationsFilters.setProductId("prod-pagopa"); + doNothing().when(notificationEventService).send(any(), any(), any(), any()); + when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(getMockedList(100)); - ResendNotificationsFilters nextFilter = notificationEventResenderServiceDefault.resendNotifications(resendNotificationsFilters, context); + // Act + ResendNotificationsFilters resendNotificationsFilters = notificationEventResenderServiceDefault.resendNotifications(filters, context); - assertNull(nextFilter); + // Assert + verify(notificationEventService, times(100)).send(any(), any(), any(), any()); + verify(onboardingService).getOnboardingsToResend(filters, 0, 100); + assertNotNull(resendNotificationsFilters); + assertEquals(1, resendNotificationsFilters.getPage()); } - private List mockOnboardingList(int size) { + private List getMockedList(int i) { List onboardings = new ArrayList<>(); - for (int i = 0; i < size; i++) { + for(int j = 0; j < i; j++) { Onboarding onboarding = new Onboarding(); - onboarding.setId("id" + i); + onboarding.setId("id" + j); + onboarding.setStatus(OnboardingStatus.COMPLETED); + onboarding.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); onboardings.add(onboarding); } + return onboardings; } } \ No newline at end of file