Skip to content

Commit

Permalink
[SELC-5465] fix: Calculation of moduleOfEpoch Attribute Based on Onbo…
Browse files Browse the repository at this point in the history
…arding Creation Date (#28)
  • Loading branch information
manuraf authored Sep 2, 2024
1 parent dc871a8 commit 0c92089
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@ mscore.aws-ses-secret-id=${AWS_SES_ACCESS_KEY_ID:secret-id-example}
mscore.aws-ses-secret-key=${AWS_SES_SECRET_ACCESS_KEY:secret-key-example}
mscore.aws-ses-region=${AWS_SES_REGION:eu-south-1}

mscore.sending-frequency-pec-notification=${SENDING_FREQUENCY_PEC_NOTIFICATION:30}
mscore.epoch-date-pec-notification=${EPOCH_DATE_PEC_NOTIFICATION:2024-01-01}

## NOTIFICATION PRODUCT SENDING FREQUENCY ##
mscore.institution-send-mail.epoch-date-pec-notification=${EPOCH_DATE_PEC_NOTIFICATION:2024-01-01}
mscore.institution-send-mail.scheduler.pec-notification-disabled=${PEC_NOTIFICATION_DISABLED:false}

mscore.institution-send-mail.scheduler.products.prod-interop=30
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@ConfigurationProperties(prefix = "mscore.institution-send-mail.scheduler")
public class InstitutionSendMailConfig {

String epochDatePecNotification;
Boolean pecNotificationDisabled;
Map<String, Integer> products;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
import it.pagopa.selfcare.mscore.model.onboarding.VerifyOnboardingFilters;
import it.pagopa.selfcare.mscore.model.pecnotification.PecNotification;
import lombok.extern.slf4j.Slf4j;

import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

Expand All @@ -36,26 +34,19 @@ public class OnboardingServiceImpl implements OnboardingService {
private final InstitutionService institutionService;
private final InstitutionConnector institutionConnector;
private final PecNotificationConnector pecNotificationConnector;
private final Integer sendingFrequencyPecNotification;
private final String epochDatePecNotification;
private final LocalDate currentDate = LocalDate.now();

private final InstitutionSendMailConfig institutionSendMailConfig;

public OnboardingServiceImpl(OnboardingDao onboardingDao,
InstitutionService institutionService,
InstitutionConnector institutionConnector,
PecNotificationConnector pecNotificationConnector,
@Value("${mscore.sending-frequency-pec-notification}") Integer sendingFrequencyPecNotification,
@Value("${mscore.epoch-date-pec-notification}") String epochDatePecNotification,
InstitutionSendMailConfig institutionSendMailConfig) {

this.onboardingDao = onboardingDao;
this.institutionService = institutionService;
this.institutionConnector = institutionConnector;
this.pecNotificationConnector = pecNotificationConnector;
this.sendingFrequencyPecNotification = sendingFrequencyPecNotification;
this.epochDatePecNotification = epochDatePecNotification;
this.institutionSendMailConfig = institutionSendMailConfig;
}

Expand Down Expand Up @@ -85,7 +76,7 @@ public void verifyOnboardingInfoByFilters(VerifyOnboardingFilters filters) {
}
}

public void insertPecNotification(String institutionId, String productId, String digitalAddress) {
public void insertPecNotification(String institutionId, String productId, String digitalAddress, OffsetDateTime createdAtOnboarding) {

//If sending mail ActiveUsers enabled for this product
if (!institutionSendMailConfig.getPecNotificationDisabled()
Expand All @@ -96,7 +87,8 @@ public void insertPecNotification(String institutionId, String productId, String
pecNotification.setCreatedAt(Instant.now());
pecNotification.setProductId(productId);
pecNotification.setInstitutionId(institutionId);
pecNotification.setModuleDayOfTheEpoch(calculateModuleDayOfTheEpoch());
pecNotification.setModuleDayOfTheEpoch(calculateModuleDayOfTheEpoch(institutionSendMailConfig.getEpochDatePecNotification(),
createdAtOnboarding, institutionSendMailConfig.getProducts().get(productId)));
pecNotification.setDigitalAddress(digitalAddress);

if (!pecNotificationConnector.insertPecNotification(pecNotification)) {
Expand All @@ -106,18 +98,18 @@ public void insertPecNotification(String institutionId, String productId, String

}

public int calculateModuleDayOfTheEpoch() {
LocalDate epochStart = LocalDate.parse(this.epochDatePecNotification);
long daysDiff = ChronoUnit.DAYS.between(epochStart, this.currentDate);
return (int) (daysDiff % this.sendingFrequencyPecNotification);
public int calculateModuleDayOfTheEpoch(String epochDatePecNotification, OffsetDateTime createdAtOnboarding, Integer sendingFrequencyPecNotification) {
LocalDate epochStart = LocalDate.parse(epochDatePecNotification);
long daysDiff = ChronoUnit.DAYS.between(epochStart, createdAtOnboarding);
return (int) (daysDiff % sendingFrequencyPecNotification);
}

@Override
public Institution persistOnboarding(String institutionId, String
productId, Onboarding onboarding, StringBuilder httpStatus) {

Institution institution = persistAndGetInstitution(institutionId, productId, onboarding, httpStatus);
insertPecNotification(institutionId, productId, institution.getDigitalAddress());
insertPecNotification(institutionId, productId, institution.getDigitalAddress(), onboarding.getCreatedAt());

return institution;
}
Expand All @@ -139,7 +131,7 @@ private Institution persistAndGetInstitution(String institutionId, String produc
.filter(item -> item.getProductId().equals(productId) && UtilEnumList.VALID_RELATIONSHIP_STATES.contains(item.getStatus()))
.findAny()).isPresent()) {

httpStatus.append(HttpStatus.OK.value());
httpStatus.append(HttpStatus.OK.value());
return institution;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
import it.pagopa.selfcare.mscore.model.institution.Billing;
import it.pagopa.selfcare.mscore.model.institution.Institution;
import it.pagopa.selfcare.mscore.model.institution.Onboarding;
import it.pagopa.selfcare.mscore.model.onboarding.*;
import it.pagopa.selfcare.mscore.model.onboarding.Token;
import it.pagopa.selfcare.mscore.model.onboarding.VerifyOnboardingFilters;
import it.pagopa.selfcare.mscore.model.pecnotification.PecNotification;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
Expand All @@ -22,18 +23,20 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.util.ReflectionTestUtils;


import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static it.pagopa.selfcare.mscore.constant.GenericError.DELETE_NOTIFICATION_OPERATION_ERROR;
import static it.pagopa.selfcare.mscore.constant.GenericError.ONBOARDING_OPERATION_ERROR;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

@ContextConfiguration(classes = {OnboardingServiceImpl.class})
Expand Down Expand Up @@ -139,9 +142,6 @@ void testVerifyOnboardingInfo5() {
@Test
void persistOnboarding_whenUserExistsOnRegistry() {

ReflectionTestUtils.setField(onboardingServiceImpl, "sendingFrequencyPecNotification", 30);
ReflectionTestUtils.setField(onboardingServiceImpl, "epochDatePecNotification", "2024-01-01");

Onboarding onboarding = dummyOnboarding();
onboarding.setStatus(UtilEnumList.VALID_RELATIONSHIP_STATES.get(0));
Institution institution = new Institution();
Expand All @@ -152,6 +152,7 @@ void persistOnboarding_whenUserExistsOnRegistry() {
when(institutionConnector.findById(institution.getId())).thenReturn(institution);
when(institutionSendMailConfig.getPecNotificationDisabled()).thenReturn(false);
when(institutionSendMailConfig.getProducts()).thenReturn(Map.of(onboarding.getProductId(),30));
when(institutionSendMailConfig.getEpochDatePecNotification()).thenReturn("2024-01-01");

String institutionId = institution.getId();

Expand All @@ -169,9 +170,6 @@ void persistOnboarding_whenUserExistsOnRegistry() {
@Test
void persistOnboarding_whenPecNotificationIsDisabled() {

ReflectionTestUtils.setField(onboardingServiceImpl, "sendingFrequencyPecNotification", 30);
ReflectionTestUtils.setField(onboardingServiceImpl, "epochDatePecNotification", "2024-01-01");

Onboarding onboarding = dummyOnboarding();
onboarding.setStatus(UtilEnumList.VALID_RELATIONSHIP_STATES.get(0));
Institution institution = new Institution();
Expand Down Expand Up @@ -236,9 +234,6 @@ void persistOnboarding_shouldRollback() {
@Test
void persistOnboarding_whenUserNotExistsOnRegistry() {

ReflectionTestUtils.setField(onboardingServiceImpl, "sendingFrequencyPecNotification", 30);
ReflectionTestUtils.setField(onboardingServiceImpl, "epochDatePecNotification", "2024-01-01");

String pricingPlan = "pricingPlan";
String productId = "productId";
Billing billing = new Billing();
Expand Down Expand Up @@ -274,6 +269,7 @@ void persistOnboarding_whenUserNotExistsOnRegistry() {
when(institutionConnector.findAndUpdate(any(), any(), any(), any())).thenReturn(institution);
when(institutionSendMailConfig.getPecNotificationDisabled()).thenReturn(false);
when(institutionSendMailConfig.getProducts()).thenReturn(Map.of(productId,30));
when(institutionSendMailConfig.getEpochDatePecNotification()).thenReturn("2024-01-01");

StringBuilder statusCode = new StringBuilder();

Expand Down Expand Up @@ -344,15 +340,37 @@ void deleteOnboardedInstitution_deletePecNotificationFails() {
verify(pecNotificationConnector, times(1)).findAndDeletePecNotification(institutionId, productId);
}



@Test
public void testCalculateModuleDayOfTheEpoch() {
LocalDate mockCurrentDate = LocalDate.of(2024, 2, 1); // 31 days after epoch
public void insertPecNotification() {
String institutionId = "testInstitution";
String productId = "testProduct";
String digitalAddress = "[email protected]";
OffsetDateTime createdAtOnboarding = OffsetDateTime.of(2024, 8, 30, 10, 0, 0, 0, ZoneOffset.UTC);

Map<String, Integer> products = new HashMap<>();
products.put(productId, 30);

ReflectionTestUtils.setField(onboardingServiceImpl, "sendingFrequencyPecNotification", 30);
ReflectionTestUtils.setField(onboardingServiceImpl, "epochDatePecNotification", "2024-01-01");
ReflectionTestUtils.setField(onboardingServiceImpl, "currentDate", mockCurrentDate);
when(institutionSendMailConfig.getPecNotificationDisabled()).thenReturn(false);
when(institutionSendMailConfig.getProducts()).thenReturn(products);
when(institutionSendMailConfig.getEpochDatePecNotification()).thenReturn("2024-01-01");
when(pecNotificationConnector.insertPecNotification(any())).thenReturn(true);

// Act
onboardingServiceImpl.insertPecNotification(institutionId, productId, digitalAddress, createdAtOnboarding);

// Assert
ArgumentCaptor<PecNotification> argumentCaptor = ArgumentCaptor.forClass(PecNotification.class);
verify(pecNotificationConnector, times(1)).insertPecNotification(argumentCaptor.capture());
assertEquals(2, argumentCaptor.getValue().getModuleDayOfTheEpoch());
}

@Test
public void testCalculateModuleDayOfTheEpoch() {
OffsetDateTime mockCurrentDate = OffsetDateTime.of(2024, 2, 1, 0, 0, 0, 0, ZoneOffset.UTC); // 31 days after epoch

int result = onboardingServiceImpl.calculateModuleDayOfTheEpoch();
int result = onboardingServiceImpl.calculateModuleDayOfTheEpoch("2024-01-01", mockCurrentDate, 30);

LocalDate epochStart = LocalDate.parse("2024-01-01");
long daysDiff = ChronoUnit.DAYS.between(epochStart, mockCurrentDate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,15 @@ private Uni<Void> retrieveFilteredAndPaginatedPecNotification(Long moduleDayOfTh
return Multi.createBy().repeating()
.uni(AtomicInteger::new,
currentPage -> runQueryAndSendNotification(moduleDayOfTheEpoch, currentPage.getAndIncrement(), productId))
.withDelay(Duration.ofSeconds(30))
.until(Boolean.FALSE::equals)
.collect()
.asList()
.replaceWith(Uni.createFrom().voidItem());

}

private Uni<Boolean> runQueryAndSendNotification(Long moduleDayOfTheEpoch, int page, String productId) {
public Uni<Boolean> runQueryAndSendNotification(Long moduleDayOfTheEpoch, int page, String productId) {
var pecNotificationPage = PecNotification.find(PecNotification.Fields.moduleDayOfTheEpoch.name() + "=?1 AND "
+ PecNotification.Fields.productId.name() + "=?2", moduleDayOfTheEpoch, productId)
.page(page, querySize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ institution-send-mail.destination-mail = ${MAIL_DESTINATION_TEST:true}
## If MAIL_DESTINATION_TEST is true, app send mail to this address
institution-send-mail.destination-mail-test-address = ${MAIL_DESTINATION_TEST_ADDRESS:[email protected]}

institution-send-mail.notification-path= ${MAIL_TEMPLATE_NOTIFICATION_PATH:test.json}
institution-send-mail.first-notification-path =${MAIL_TEMPLATE_FIRST_NOTIFICATION_PATH:test.json}
institution-send-mail.notification-path= ${MAIL_TEMPLATE_NOTIFICATION_PATH:contracts/template/mail/institution-user-list-notification/1.0.0.json}
institution-send-mail.first-notification-path =${MAIL_TEMPLATE_FIRST_NOTIFICATION_PATH:contracts/template/mail/institution-user-list-first-notification/1.0.0.json}

institution-send-mail.notification-query-size = 1000
institution-send-mail.notification-query-size = ${MAIL_QUERY_SIZE:10}
institution-send-mail.notification-start-date = 2024-01-01
institution-send-mail.notification-send-all = ${SEND_ALL_NOTIFICATION:false}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import it.pagopa.selfcare.product.entity.Product;
import it.pagopa.selfcare.product.service.ProductService;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
Expand All @@ -28,8 +29,6 @@

@QuarkusTest
class InstitutionSendMailScheduledServiceImplTest {

public static final int PAGE_SIZE = 1000;
@InjectMock
MailServiceImpl mailService;

Expand All @@ -43,6 +42,9 @@ class InstitutionSendMailScheduledServiceImplTest {
@InjectMock
InstitutionApi institutionApi;

@ConfigProperty(name = "institution-send-mail.notification-query-size")
Integer querySize;

@Test
void sendMailToAllPecNotificationsForCurrentModuleDay() {
String institutionId = "institution-id";
Expand All @@ -52,11 +54,11 @@ void sendMailToAllPecNotificationsForCurrentModuleDay() {
ReactivePanacheQuery<ReactivePanacheMongoEntityBase> query = Mockito.mock(ReactivePanacheQuery.class);
when(PecNotification.find(any(), any(Object.class)))
.thenReturn(query);
when(query.page(0, PAGE_SIZE)).thenReturn(query);
when(query.page(0, querySize)).thenReturn(query);


ReactivePanacheQuery<ReactivePanacheMongoEntityBase> query2 = Mockito.mock(ReactivePanacheQuery.class);
when(query.page(1, PAGE_SIZE)).thenReturn(query2);
when(query.page(1, querySize)).thenReturn(query2);
when(query.hasNextPage()).thenReturn(Uni.createFrom().item(true));
when(query.firstResult()).thenReturn(Uni.createFrom().item(notifications.get(0)));

Expand All @@ -77,7 +79,7 @@ void sendMailToAllPecNotificationsForCurrentModuleDay() {

Uni<Void> result = service.retrieveInstitutionFromPecNotificationAndSendMail();
UniAssertSubscriber<Void> subscriber = result.subscribe().withSubscriber(UniAssertSubscriber.create());
subscriber.assertCompleted();
subscriber.assertNotTerminated();
Mockito.verify(mailService, Mockito.atLeast(4))
.sendMail(Mockito.anyList(), Mockito.anyString(), Mockito.anyMap());
}
Expand All @@ -96,7 +98,7 @@ void shouldNotSendMail_whenOnboardingHappenToday() {
ReactivePanacheQuery<ReactivePanacheMongoEntityBase> query = Mockito.mock(ReactivePanacheQuery.class);
when(PecNotification.find(any(), any(Object.class)))
.thenReturn(query);
when(query.page(0, PAGE_SIZE)).thenReturn(query);
when(query.page(0, querySize)).thenReturn(query);


when(query.hasNextPage()).thenReturn(Uni.createFrom().item(false));
Expand All @@ -111,6 +113,8 @@ void shouldNotSendMail_whenOnboardingHappenToday() {

@Test
void shouldLogErrorAndContinueOnMailSendFailure() {
final int page = 0;
final long moduleDayOfTheEpoch = 1L;
// Setup mocks
PecNotification notification1 = new PecNotification();
notification1.setProductId("product-id");
Expand All @@ -122,7 +126,7 @@ void shouldLogErrorAndContinueOnMailSendFailure() {
ReactivePanacheQuery<ReactivePanacheMongoEntityBase> query = Mockito.mock(ReactivePanacheQuery.class);
when(PecNotification.find(any(), any(Object.class)))
.thenReturn(query);
when(query.page(0, 1000)).thenReturn(query);
when(query.page(0, querySize)).thenReturn(query);
when(query.hasNextPage()).thenReturn(Uni.createFrom().item(false));
when(query.firstResult()).thenReturn(Uni.createFrom().item(notification1));
Product product = new Product();
Expand All @@ -131,26 +135,27 @@ void shouldLogErrorAndContinueOnMailSendFailure() {
Mockito.doThrow(new RuntimeException("Mail send failed")).when(mailService).sendMail(Mockito.anyList(), Mockito.anyString(), Mockito.anyMap());

// Execute
Uni<Void> result = service.retrieveInstitutionFromPecNotificationAndSendMail();
UniAssertSubscriber<Void> subscriber = result.subscribe().withSubscriber(UniAssertSubscriber.create());
Uni<Boolean> result = service.runQueryAndSendNotification(moduleDayOfTheEpoch, page, "productId");
UniAssertSubscriber<Boolean> subscriber = result.subscribe().withSubscriber(UniAssertSubscriber.create());

// Verify
subscriber.assertFailedWith(RuntimeException.class, "Mail send failed");
}

@Test
void shouldHandleNoPecNotificationsForCurrentModuleDay() {
final int page = 0;
PanacheMock.mock(PecNotification.class);
ReactivePanacheQuery<ReactivePanacheMongoEntityBase> query = Mockito.mock(ReactivePanacheQuery.class);
when(PecNotification.find(any(), any(Object.class)))
.thenReturn(query);
when(query.page(0, 1000)).thenReturn(query);
when(query.page(page, querySize)).thenReturn(query);
when(query.hasNextPage()).thenReturn(Uni.createFrom().item(false));
when(query.firstResult()).thenReturn(Uni.createFrom().nullItem());

// Execute
Uni<Void> result = service.retrieveInstitutionFromPecNotificationAndSendMail();
UniAssertSubscriber<Void> subscriber = result.subscribe().withSubscriber(UniAssertSubscriber.create());
Uni<Boolean> result = service.runQueryAndSendNotification(0L, page, "productId");
UniAssertSubscriber<Boolean> subscriber = result.subscribe().withSubscriber(UniAssertSubscriber.create());

// Verify
Mockito.verify(mailService, Mockito.never()).sendMail(Mockito.anyList(), Mockito.anyString(), Mockito.anyMap());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module "mongodb_collection_pec_notifications" {
unique = true
},
{
keys = ["moduleDayOfTheEpoch"]
keys = ["moduleDayOfTheEpoch","productId"]
unique = false
}
]
Expand Down

0 comments on commit 0c92089

Please sign in to comment.