FINERACT-1678-loan-cob-drop-softlocking-use-lastclosedbusinessdate

This commit is contained in:
Ruchi Dhamankar
2023-05-26 12:48:44 +02:00
committed by Adam Saghy
parent 005af94291
commit e9bc0fe8c2
18 changed files with 66 additions and 380 deletions
@@ -83,10 +83,9 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
lenient().when(loanLockingService.findAllByLoanIdIn(Mockito.anyList())).thenThrow(new RuntimeException("fail"));
} else {
LoanAccountLock lock1 = new LoanAccountLock(1L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()));
LoanAccountLock lock2 = new LoanAccountLock(2L, LockOwner.LOAN_COB_PARTITIONING, LocalDate.now(ZoneId.systemDefault()));
LoanAccountLock lock3 = new LoanAccountLock(3L, LockOwner.LOAN_INLINE_COB_PROCESSING,
LocalDate.now(ZoneId.systemDefault()));
List<LoanAccountLock> accountLocks = List.of(lock1, lock2, lock3);
List<LoanAccountLock> accountLocks = List.of(lock1, lock3);
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanLockingService.findAllByLoanIdIn(Mockito.anyList())).thenReturn(accountLocks);
@@ -101,7 +100,7 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
Then("ApplyLoanLockTasklet.execute result should match", () -> {
assertEquals(RepeatStatus.FINISHED, resultItem);
verify(loanLockingService, Mockito.times(1)).upgradeLock(valueCaptor.capture(), lockOwnerValueCaptor.capture());
verify(loanLockingService, Mockito.times(1)).applyLock(valueCaptor.capture(), lockOwnerValueCaptor.capture());
List<Long> values = valueCaptor.getValue();
assertEquals(2L, values.get(0));
assertEquals(LockOwner.LOAN_COB_CHUNK_PROCESSING, lockOwnerValueCaptor.getValue());
@@ -1,178 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.cob.loan;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import io.cucumber.java8.En;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import org.apache.fineract.cob.common.CustomJobParameterResolver;
import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.repeat.RepeatStatus;
public class FetchAndLockLoanStepDefinitions implements En {
private final LoanAccountLockRepository loanAccountLockRepository = mock(LoanAccountLockRepository.class);
private final FineractProperties fineractProperties = mock(FineractProperties.class);
private final FineractProperties.FineractQueryProperties fineractQueryProperties = mock(
FineractProperties.FineractQueryProperties.class);
StepContribution contribution;
ArgumentCaptor<LocalDate> dateValueCaptor = ArgumentCaptor.forClass(LocalDate.class);
ArgumentCaptor<LoanCOBParameter> loanCOBParameterValueCaptor = ArgumentCaptor.forClass(LoanCOBParameter.class);
ArgumentCaptor<Boolean> isCatchUpParameterCaptor = ArgumentCaptor.forClass(Boolean.class);
private LockLoanTasklet lockLoanTasklet;
private String action;
private RepeatStatus result;
private final LoanLockingService loanLockingService = mock(LoanLockingService.class);
private final CustomJobParameterResolver customJobParameterResolver = mock(CustomJobParameterResolver.class);
public FetchAndLockLoanStepDefinitions() {
Given("/^The FetchAndLockLoanTasklet.execute method with action (.*)$/", (String action) -> {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
HashMap<BusinessDateType, LocalDate> businessDateMap = new HashMap<>();
businessDateMap.put(BusinessDateType.COB_DATE, LocalDate.now(ZoneId.systemDefault()));
ThreadLocalContextUtil.setBusinessDates(businessDateMap);
this.action = action;
JobExecution jobExecution = new JobExecution(1L);
StepExecution stepExecution = new StepExecution("step", jobExecution);
contribution = new StepContribution(stepExecution);
contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME,
LocalDate.now(ZoneId.systemDefault()).toString());
lenient().when(customJobParameterResolver.getCustomJobParameterSet(Mockito.any())).thenReturn(Optional.empty());
if ("empty loanIds".equals(action)) {
contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
new LoanCOBParameter(0L, 0L));
} else if ("good".equals(action)) {
contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(Collections.emptyList());
} else if ("soft lock".equals(action)) {
contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(
List.of(new LoanAccountLock(1L, LockOwner.LOAN_COB_PARTITIONING, LocalDate.now(ZoneId.systemDefault()))));
} else if ("inline cob".equals(action)) {
contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(
List.of(new LoanAccountLock(2L, LockOwner.LOAN_INLINE_COB_PROCESSING, LocalDate.now(ZoneId.systemDefault()))));
} else if ("chunk processing".equals(action)) {
contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(
List.of(new LoanAccountLock(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()))));
}
lockLoanTasklet = new LockLoanTasklet(loanLockingService, customJobParameterResolver);
});
When("FetchAndLockLoanTasklet.execute method executed", () -> {
result = lockLoanTasklet.execute(contribution, null);
});
Then("FetchAndLockLoanTasklet.execute result should match", () -> {
if ("empty steps".equals(action)) {
assertEquals(RepeatStatus.FINISHED, result);
} else if ("good".equals(action)) {
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture(),
isCatchUpParameterCaptor.capture());
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
assertEquals(RepeatStatus.FINISHED, result);
assertEquals(false, isCatchUpParameterCaptor.getValue());
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
assertEquals(1L, loanCOBParameter.getMinLoanId());
assertEquals(3L, loanCOBParameter.getMaxLoanId());
} else if ("soft lock".equals(action)) {
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture(),
isCatchUpParameterCaptor.capture());
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
assertEquals(RepeatStatus.FINISHED, result);
assertEquals(false, isCatchUpParameterCaptor.getValue());
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
assertEquals(1L, loanCOBParameter.getMinLoanId());
assertEquals(3L, loanCOBParameter.getMaxLoanId());
} else if ("inline cob".equals(action)) {
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture(),
isCatchUpParameterCaptor.capture());
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
assertEquals(RepeatStatus.FINISHED, result);
assertEquals(false, isCatchUpParameterCaptor.getValue());
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
assertEquals(1L, loanCOBParameter.getMinLoanId());
assertEquals(3L, loanCOBParameter.getMaxLoanId());
} else if ("chunk processing".equals(action)) {
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture(),
isCatchUpParameterCaptor.capture());
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
assertEquals(RepeatStatus.FINISHED, result);
assertEquals(false, isCatchUpParameterCaptor.getValue());
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
assertEquals(1L, loanCOBParameter.getMinLoanId());
assertEquals(3L, loanCOBParameter.getMaxLoanId());
}
});
}
}
@@ -193,7 +193,6 @@ class LoanCOBApiFilterTest {
given(request.getPathInfo()).willReturn("/v1/loans/2/charges");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(false);
given(context.authenticatedUser()).willReturn(appUser);
given(fineractProperties.getQuery()).willReturn(fineractQueryProperties);
given(fineractQueryProperties.getInClauseParameterSizeLimit()).willReturn(65000);
@@ -221,7 +220,6 @@ class LoanCOBApiFilterTest {
given(request.getPathInfo()).willReturn("/v1/loans/external-id/" + uuid + "/charges");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(false);
given(context.authenticatedUser()).willReturn(appUser);
given(loanRepository.findIdByExternalId(any())).willReturn(2L);
given(fineractProperties.getQuery()).willReturn(fineractQueryProperties);
@@ -250,7 +248,6 @@ class LoanCOBApiFilterTest {
given(request.getPathInfo()).willReturn("/v1/rescheduleloans/" + resourceId + "/charges");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(false);
given(fineractProperties.getQuery()).willReturn(fineractQueryProperties);
given(fineractQueryProperties.getInClauseParameterSizeLimit()).willReturn(65000);
LoanRescheduleRequest rescheduleRequest = mock(LoanRescheduleRequest.class);
@@ -265,24 +262,6 @@ class LoanCOBApiFilterTest {
verify(filterChain, times(1)).doFilter(request, response);
}
@Test
void shouldRunInlineCOBAndProceedWhenLoanIsSoftLocked() throws ServletException, IOException {
MockHttpServletRequest request = mock(MockHttpServletRequest.class);
MockHttpServletResponse response = mock(MockHttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);
AppUser appUser = mock(AppUser.class);
given(request.getPathInfo()).willReturn("/v1/loans/2/charges");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(true);
given(context.authenticatedUser()).willReturn(appUser);
testObj.doFilterInternal(request, response, filterChain);
verify(inlineLoanCOBExecutorService, times(1)).execute(Collections.singletonList(2L), "INLINE_LOAN_COB");
verify(filterChain, times(1)).doFilter(request, response);
}
@Test
void shouldRunInlineCOBAndProceedWhenLoanIsBehind() throws ServletException, IOException {
MockHttpServletRequest request = mock(MockHttpServletRequest.class);
@@ -299,16 +278,15 @@ class LoanCOBApiFilterTest {
LoanIdAndLastClosedBusinessDate result = mock(LoanIdAndLastClosedBusinessDate.class);
given(result.getId()).willReturn(2L);
given(result.getLastClosedBusinessDate()).willReturn(businessDate.minusDays(2));
given(request.getPathInfo()).willReturn("/v1/loans/2?command=approve");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(true);
given(fineractProperties.getQuery()).willReturn(fineractQueryProperties);
given(fineractQueryProperties.getInClauseParameterSizeLimit()).willReturn(65000);
given(loanRepository.findAllNonClosedLoansBehindOrNullByLoanIds(
given(loanRepository.findAllNonClosedLoansBehindByLoanIds(
eq(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)), anyList()))
.willReturn(Collections.singletonList(result));
given(context.authenticatedUser()).willReturn(appUser);
testObj.doFilterInternal(request, response, filterChain);
@@ -335,7 +313,6 @@ class LoanCOBApiFilterTest {
given(request.getPathInfo()).willReturn("/v1/loans/2?command=approve");
given(request.getMethod()).willReturn(HTTPMethods.POST.value());
given(loanAccountLockService.isLoanHardLocked(2L)).willReturn(false);
given(loanAccountLockService.isLoanSoftLocked(2L)).willReturn(false);
given(fineractProperties.getQuery()).willReturn(fineractQueryProperties);
given(fineractQueryProperties.getInClauseParameterSizeLimit()).willReturn(65000);
given(loanRepository.findAllNonClosedLoansBehindOrNullByLoanIds(
@@ -1,34 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
Feature: COB Loan fetch and (soft) lock Step
@cob
Scenario Outline: FetchAndLockLoanTasklet - run test
Given The FetchAndLockLoanTasklet.execute method with action <action>
When FetchAndLockLoanTasklet.execute method executed
Then FetchAndLockLoanTasklet.execute result should match
Examples:
|action|
|empty loanIds|
|good|
|soft lock|
|inline cob|
|chunk processing|