FINERACT-1977: 4-eye-principle, maker-checker permission

This commit is contained in:
jmarta
2024-01-11 11:46:32 +01:00
committed by Adam Saghy
parent 2fe1b0e7d3
commit 16eac933d6
69 changed files with 887 additions and 359 deletions
@@ -38,6 +38,7 @@ import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.EnumOp
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
import org.apache.fineract.portfolio.savings.data.SavingsActivation;
@@ -147,7 +148,9 @@ public class SavingsImportHandler implements ImportHandler {
Long interestPostingPeriodTypeId = null;
EnumOptionData interestPostingPeriodTypeEnum = null;
if (interestPostingPeriodType != null) {
if (interestPostingPeriodType.equalsIgnoreCase(MONTHLY)) {
if (interestPostingPeriodType.equalsIgnoreCase(DAILY)) {
interestPostingPeriodTypeId = SavingsPostingInterestPeriodType.DAILY.getValue().longValue();
} else if (interestPostingPeriodType.equalsIgnoreCase(MONTHLY)) {
interestPostingPeriodTypeId = 4L;
} else if (interestPostingPeriodType.equalsIgnoreCase(QUARTERLY)) {
interestPostingPeriodTypeId = 5L;
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.infrastructure.configuration.domain;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -74,6 +75,11 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
return false;
}
@Override
public boolean isSameMakerCheckerEnabled() {
return getGlobalConfigurationPropertyData("enable-same-maker-checker").isEnabled();
}
@Override
public boolean isAmazonS3Enabled() {
return getGlobalConfigurationPropertyData("amazon-S3").isEnabled();
@@ -379,18 +385,14 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
return property.getValue();
}
@NotNull
private GlobalConfigurationPropertyData getGlobalConfigurationPropertyData(final String propertyName) {
return globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName).toData();
}
@Override
public boolean isSubRatesEnabled() {
GlobalConfigurationPropertyData configuration = getGlobalConfigurationPropertyData("sub-rates");
if (configuration == null) {
return false;
} else {
return configuration.isEnabled();
}
return getGlobalConfigurationPropertyData("sub-rates").isEnabled();
}
@Override
@@ -294,7 +294,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
validateParentGroupRulesBeforeClientActivation(newClient);
runEntityDatatableCheck(newClient.getId(), newClient.getLegalForm());
final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateClient(null).build();
rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser);
}
this.clientRepository.saveAndFlush(newClient);
@@ -172,16 +172,16 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
if (newGroup.isCenter()) {
final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateCenter(null).build();
rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser);
} else {
final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateGroup(null).build();
rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser);
}
}
if (!newGroup.isCenter() && newGroup.hasActiveClients()) {
final CommandWrapper commandWrapper = new CommandWrapperBuilder().associateClientsToGroup(newGroup.getId()).build();
rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser);
rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser);
}
// pre-save to generate id for use in group hierarchy
@@ -656,7 +656,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
public CommandProcessingResult createActiveApplication(final SavingsAccountDataDTO savingsAccountDataDTO) {
final CommandWrapper commandWrapper = new CommandWrapperBuilder().savingsAccountActivation(null).build();
boolean rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, savingsAccountDataDTO.getAppliedBy());
boolean rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper,
savingsAccountDataDTO.getAppliedBy());
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsAccountDataDTO.getClient(),
savingsAccountDataDTO.getGroup(), savingsAccountDataDTO.getSavingsProduct(), savingsAccountDataDTO.getApplicationDate(),
@@ -150,4 +150,5 @@
<include file="parts/0128_savings_audit.xml" relativeToChangelogFile="true" />
<include file="parts/0129_transaction_summary_with_asset_owner_report_overpaid_amount.xml" relativeToChangelogFile="true" />
<include file="parts/0130_add_create_delinquency_action_permission.xml" relativeToChangelogFile="true" />
<include file="parts/0131_add_configuration_maker_checker.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1">
<insert tableName="c_configuration">
<column name="name" value="enable-same-maker-checker"/>
<column name="value"/>
<column name="date_value"/>
<column name="string_value"/>
<column name="enabled" valueBoolean="false"/>
<column name="is_trap_door" valueBoolean="false"/>
<column name="description"/>
</insert>
</changeSet>
</databaseChangeLog>
@@ -66,7 +66,11 @@ public class LoanItemListenerStepDefinitions implements En {
});
When("LoanItemListener.onReadError method executed", () -> {
loanItemListener.onReadError(exception);
try {
loanItemListener.onReadError(exception);
} finally {
ThreadLocalContextUtil.reset();
}
});
Then("LoanItemListener.onReadError result should match", () -> {
@@ -87,7 +91,11 @@ public class LoanItemListenerStepDefinitions implements En {
});
When("LoanItemListener.onProcessError method executed", () -> {
loanItemListener.onProcessError(loan, exception);
try {
loanItemListener.onProcessError(loan, exception);
} finally {
ThreadLocalContextUtil.reset();
}
});
Then("LoanItemListener.onProcessError result should match", () -> {
@@ -108,7 +116,11 @@ public class LoanItemListenerStepDefinitions implements En {
});
When("LoanItemListener.onWriteError method executed", () -> {
loanItemListener.onWriteError(exception, new Chunk<>(List.of(loan)));
try {
loanItemListener.onWriteError(exception, new Chunk<>(List.of(loan)));
} finally {
ThreadLocalContextUtil.reset();
}
});
Then("LoanItemListener.onWriteError result should match", () -> {
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualPlatformService;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -66,6 +67,11 @@ public class AddPeriodicAccrualEntriesBusinessStepTest {
underTest = new AddPeriodicAccrualEntriesBusinessStep(loanAccrualPlatformService);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void givenLoanWithAccrual() throws MultiException {
// given
@@ -122,7 +122,11 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
});
When("ApplyLoanLockTasklet.execute method executed", () -> {
resultItem = applyLoanLockTasklet.execute(stepContribution, null);
try {
resultItem = applyLoanLockTasklet.execute(stepContribution, null);
} finally {
ThreadLocalContextUtil.reset();
}
});
Then("ApplyLoanLockTasklet.execute result should match", () -> {
@@ -46,6 +46,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -72,6 +73,11 @@ public class CheckLoanRepaymentDueBusinessStepTest {
underTest = new CheckLoanRepaymentDueBusinessStep(configurationDomainService, businessEventNotifierService);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void givenLoanWithInstallmentDueAfterConfiguredDaysWhenStepExecutionThenBusinessEventIsRaised() {
ArgumentCaptor<LoanRepaymentDueBusinessEvent> loanRepaymentDueEvent = ArgumentCaptor.forClass(LoanRepaymentDueBusinessEvent.class);
@@ -43,6 +43,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -69,6 +70,11 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
underTest = new CheckLoanRepaymentOverdueBusinessStep(configurationDomainService, businessEventNotifierService);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void givenLoanWithInstallmentOverdueAfterConfiguredDaysWhenStepExecutionThenBusinessEventIsRaised() {
ArgumentCaptor<LoanRepaymentOverdueBusinessEvent> loanRepaymentDueBusinessEventArgumentCaptor = ArgumentCaptor
@@ -169,5 +175,4 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
assertEquals(repaymentInstallment, loanPayloadForEvent);
assertEquals(processedLoan, loanForProcessing);
}
}
@@ -40,6 +40,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -73,6 +74,11 @@ class LoanItemReaderTest {
@Mock
private Loan loan;
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void testLoanItemReaderSimple() throws Exception {
// given
@@ -163,5 +169,4 @@ class LoanItemReaderTest {
Mockito.verifyNoMoreInteractions(loanRepository);
}
}
@@ -47,6 +47,7 @@ import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePaus
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -100,6 +101,11 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
delinquencyReadPlatformService, businessEventNotifierService);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
/**
* Tests {@link SetLoanDelinquencyTagsBusinessStep#execute(Loan)} success scenario.
*
@@ -85,7 +85,7 @@ public class COBBulkEventConfigurationTest {
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
ThreadLocalContextUtil.reset();
}
@Test
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
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.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -73,6 +74,11 @@ class InlineLoanCOBExecutorServiceImplTest {
@Mock
private FineractProperties.FineractBodyItemSizeLimitProperties fineractBodyItemSizeLimitProperties;
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
void shouldExceptionThrownIfLoanIsAlreadyLocked() {
JsonCommand command = mock(JsonCommand.class);
@@ -37,6 +37,7 @@ import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -71,6 +72,11 @@ public class PurgeProcessedCommandsTaskletTest {
underTest = new PurgeProcessedCommandsTasklet(repository, configurationDomainService);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void givenEventsForPurgeWhenTaskExecutionThenEventsPurgeForDaysCriteria() {
// given
@@ -97,5 +103,4 @@ public class PurgeProcessedCommandsTaskletTest {
// then
assertEquals(RepeatStatus.FINISHED, resultStatus);
}
}
@@ -25,13 +25,10 @@ import static org.mockito.ArgumentMatchers.any;
import io.cucumber.java8.En;
import io.github.resilience4j.retry.RetryRegistry;
import io.github.resilience4j.retry.event.RetryEvent;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.fineract.commands.domain.CommandSource;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.exception.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.apache.fineract.commands.exception.RollbackTransactionNotApprovedException;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder;
@@ -69,7 +66,7 @@ public class CommandServiceStepDefinitions implements En {
ReflectionTestUtils.setField(processAndLogCommandService, "fineractRequestContextHolder", contextHolder);
Mockito.when(contextHolder.getAttribute(any(), any())).thenThrow(new CannotAcquireLockException("BLOW IT UP!!!"))
.thenThrow(new ObjectOptimisticLockingFailureException("Dummy", new RuntimeException("BLOW IT UP!!!")))
.thenThrow(new RollbackTransactionAsCommandIsNotApprovedByCheckerException(new DummyCommandSource()));
.thenThrow(new RollbackTransactionNotApprovedException(1L, null));
this.retryRegistry.retry("executeCommand").getEventPublisher().onRetry(event -> {
log.warn("... retry event: {}", event);
@@ -147,13 +144,4 @@ public class CommandServiceStepDefinitions implements En {
return null;
}
}
@Entity
@Table(name = "m_portfolio_command_source")
public static class DummyCommandSource extends CommandSource {
public DummyCommandSource() {
setId(1L);
}
}
}
@@ -89,24 +89,12 @@ public class CommandSourceServiceTest {
@Test
public void testCreateFromExisting() {
CommandWrapper wrapper = CommandWrapper.wrap("act", "ent", 1L, 1L);
long commandId = 1L;
JsonCommand jsonCommand = JsonCommand.fromExistingCommand(commandId, "", null, null, null, 1L, null, null, null, null, null, null,
null, null, null, null, null);
CommandSource commandMock = Mockito.mock(CommandSource.class);
Mockito.when(commandSourceRepository.saveAndFlush(commandMock)).thenReturn(commandMock);
Mockito.when(commandSourceRepository.findById(commandId)).thenReturn(Optional.of(commandMock));
AppUser appUser = Mockito.mock(AppUser.class);
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "t1", "n1", ZoneId.systemDefault().toString(), null));
CommandSource actual = underTest.saveInitialNewTransaction(wrapper, jsonCommand, appUser, "idk");
ArgumentCaptor<CommandSource> commandSourceArgumentCaptor = ArgumentCaptor.forClass(CommandSource.class);
Mockito.verify(commandSourceRepository).saveAndFlush(commandSourceArgumentCaptor.capture());
CommandSource captured = commandSourceArgumentCaptor.getValue();
Assertions.assertEquals(actual, captured);
CommandSource actual = underTest.getCommandSource(commandId);
Assertions.assertEquals(commandMock, actual);
}
@Test
@@ -67,8 +67,6 @@ public class SynchronousCommandProcessingServiceTest {
@Mock
private IdempotencyKeyResolver idempotencyKeyResolver;
@Mock
private IdempotencyKeyGenerator idempotencyKeyGenerator;
@Mock
private CommandSourceService commandSourceService;
@Spy
@@ -93,19 +91,21 @@ public class SynchronousCommandProcessingServiceTest {
when(commandWrapper.isNoteResource()).thenReturn(false);
when(commandWrapper.isSurveyResource()).thenReturn(false);
when(commandWrapper.isLoanDisburseDetailResource()).thenReturn(false);
JsonCommand jsonCommand = Mockito.mock(JsonCommand.class);
NewCommandSourceHandler newCommandSourceHandler = Mockito.mock(NewCommandSourceHandler.class);
long commandId = 1L;
JsonCommand jsonCommand = Mockito.mock(JsonCommand.class);
when(jsonCommand.commandId()).thenReturn(commandId);
NewCommandSourceHandler commandHandler = Mockito.mock(NewCommandSourceHandler.class);
CommandProcessingResult commandProcessingResult = Mockito.mock(CommandProcessingResult.class);
when(commandProcessingResult.isRollbackTransaction()).thenReturn(false);
when(newCommandSourceHandler.processCommand(jsonCommand)).thenReturn(commandProcessingResult);
when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(newCommandSourceHandler);
when(commandHandler.processCommand(jsonCommand)).thenReturn(commandProcessingResult);
when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(commandHandler);
when(configurationDomainService.isMakerCheckerEnabledForTask(Mockito.any())).thenReturn(false);
String idk = "idk";
when(idempotencyKeyResolver.resolve(commandWrapper)).thenReturn(idk);
CommandSource commandSource = Mockito.mock(CommandSource.class);
long commandId = 1L;
when(commandSource.getId()).thenReturn(commandId);
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null);
when(commandSourceService.getCommandSource(commandId)).thenReturn(commandSource);
@@ -116,9 +116,12 @@ public class SynchronousCommandProcessingServiceTest {
when(commandSource.getStatus()).thenReturn(CommandProcessingResultType.PROCESSED.getValue());
when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser);
when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false, false))
.thenReturn(commandProcessingResult);
CommandProcessingResult actualCommandProcessingResult = underTest.executeCommand(commandWrapper, jsonCommand, false);
verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk);
verify(commandSourceService).getCommandSource(commandId);
assertEquals(CommandProcessingResultType.PROCESSED.getValue(), commandSource.getStatus());
verify(commandSourceService).saveResultSameTransaction(commandSource);
@@ -133,19 +136,21 @@ public class SynchronousCommandProcessingServiceTest {
when(commandWrapper.isSurveyResource()).thenReturn(false);
when(commandWrapper.isLoanDisburseDetailResource()).thenReturn(false);
JsonCommand jsonCommand = Mockito.mock(JsonCommand.class);
Long commandId = jsonCommand.commandId();
NewCommandSourceHandler newCommandSourceHandler = Mockito.mock(NewCommandSourceHandler.class);
NewCommandSourceHandler commandHandler = Mockito.mock(NewCommandSourceHandler.class);
CommandProcessingResult commandProcessingResult = Mockito.mock(CommandProcessingResult.class);
CommandSource commandSource = Mockito.mock(CommandSource.class);
when(commandProcessingResult.isRollbackTransaction()).thenReturn(false);
RuntimeException runtimeException = new RuntimeException("foo");
when(newCommandSourceHandler.processCommand(jsonCommand)).thenThrow(runtimeException);
when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(newCommandSourceHandler);
when(commandHandler.processCommand(jsonCommand)).thenThrow(runtimeException);
when(commandHandlerProvider.getHandler(Mockito.any(), Mockito.any())).thenReturn(commandHandler);
when(configurationDomainService.isMakerCheckerEnabledForTask(Mockito.any())).thenReturn(false);
String idk = "idk";
when(idempotencyKeyResolver.resolve(commandWrapper)).thenReturn(idk);
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null);
when(commandSourceService.getCommandSource(commandId)).thenReturn(commandSource);
AppUser appUser = Mockito.mock(AppUser.class);
when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser);
@@ -155,11 +160,14 @@ public class SynchronousCommandProcessingServiceTest {
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(initialCommandSource);
when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false, false))
.thenThrow(runtimeException);
Assertions.assertThrows(RuntimeException.class, () -> {
underTest.executeCommand(commandWrapper, jsonCommand, false);
});
verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk);
verify(commandSourceService).getCommandSource(commandId);
verify(commandSourceService).generateErrorInfo(runtimeException);
}
}
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -79,6 +80,11 @@ public class BusinessDateWritePlatformServiceTest {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void businessDateIsNotEnabled() {
JsonCommand command = JsonCommand.from("");
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDa
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -48,6 +49,11 @@ public class CustomAuditingHandlerTest {
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.of("Asia/Kolkata")))));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void markCreated() {
MappingContext mappingContext = Mockito.mock(MappingContext.class);
@@ -111,5 +117,4 @@ public class CustomAuditingHandlerTest {
assertEquals(now.getHour(), targetObject.getCreatedDate().get().getHour());
assertEquals(now.getMinute(), targetObject.getCreatedDate().get().getMinute());
}
}
@@ -28,6 +28,7 @@ import java.util.Optional;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -38,6 +39,11 @@ public class CustomDateTimeProviderTest {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void instanceDateProvider() {
Optional<TemporalAccessor> dateTimeProvider = CustomDateTimeProvider.INSTANCE.getNow();
@@ -65,5 +71,4 @@ public class CustomDateTimeProviderTest {
assertEquals(now.getHour(), ((OffsetDateTime) dateTimeProvider.get()).getHour());
assertEquals(now.getMinute(), ((OffsetDateTime) dateTimeProvider.get()).getMinute());
}
}
@@ -32,6 +32,7 @@ import java.util.Map;
import java.util.TimeZone;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -43,6 +44,11 @@ public class DateUtilsTest {
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 12))));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void getSystemZoneIdTest() {
TimeZone.setDefault(TimeZone.getTimeZone("GMT+02:00"));
@@ -21,12 +21,26 @@ package org.apache.fineract.infrastructure.dataqueries.service;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.dataqueries.service.export.DatatableExportUtil;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class DatatableExportUtilTest {
@BeforeEach
public void setUp() {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void emptyFolderTest() {
Assert.assertEquals("", DatatableExportUtil.normalizeFolderName(""));
@@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.event.external.repository.ExternalEventRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -69,6 +70,11 @@ public class PurgeExternalEventsTaskletTest {
underTest = new PurgeExternalEventsTasklet(repository, configurationDomainService);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void givenEventsForPurgeWhenTaskExecutionThenEventsPurgeForDaysCriteria() {
// given
@@ -95,5 +101,4 @@ public class PurgeExternalEventsTaskletTest {
// then
assertEquals(RepeatStatus.FINISHED, resultStatus);
}
}
@@ -47,6 +47,7 @@ import org.apache.fineract.infrastructure.event.external.repository.ExternalEven
import org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEventView;
import org.apache.fineract.infrastructure.event.external.service.message.MessageFactory;
import org.apache.fineract.infrastructure.event.external.service.support.ByteBufferConverter;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -97,6 +98,11 @@ class SendAsynchronousEventsTaskletTest {
configurationDomainService);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
private void configureExternalEventsProducerReadBatchSizeProperty() {
FineractProperties.FineractEventsProperties eventsProperties = new FineractProperties.FineractEventsProperties();
FineractProperties.FineractExternalEventsProperties externalProperties = new FineractProperties.FineractExternalEventsProperties();
@@ -26,10 +26,16 @@ import java.util.Map;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
class ExternalEventTest {
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void testConstructorWorks() {
// given
@@ -56,6 +62,5 @@ class ExternalEventTest {
assertThat(result.getBusinessDate()).isEqualTo(currentBusinessDate);
assertThat(result.getCreatedAt()).isNotNull();
assertThat(result.getSentAt()).isNull();
}
}
@@ -57,6 +57,7 @@ import org.apache.fineract.infrastructure.event.external.service.support.ByteBuf
import org.apache.fineract.investor.enricher.LoanAccountDataV1Enricher;
import org.apache.fineract.investor.enricher.LoanTransactionAdjustmentDataV1Enricher;
import org.apache.fineract.investor.enricher.LoanTransactionDataV1Enricher;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -110,6 +111,11 @@ class ExternalEventServiceTest {
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void testPostEventShouldFailWhenNullEventIsGiven() {
// given
@@ -70,6 +70,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -105,6 +106,11 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void testLoanDelinquencyRangeEventPayloadSerialization() throws IOException {
// given
@@ -340,5 +346,4 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
ReflectionTestUtils.setField(loanCharge, "id", 1L);
return loanCharge;
}
}
@@ -47,6 +47,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -78,6 +79,11 @@ public class LoanAdjustTransactionBusinessEventSerializerTest {
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
void loanTransactionReversedOnDateSerializationTest() {
Loan loanForProcessing = Mockito.mock(Loan.class);
@@ -107,5 +113,4 @@ public class LoanAdjustTransactionBusinessEventSerializerTest {
.toAvroDTO(businessEvent);
assertEquals(reversedLocalDate, loanTransactionAdjustmentDataV1.getTransactionToAdjust().getReversedOnDate());
}
}
@@ -90,6 +90,7 @@ public class LoanRepaymentBusinessEventSerializerTest {
@AfterEach
public void reset() {
ThreadLocalContextUtil.reset();
moneyHelper.close();
}
@@ -181,5 +182,4 @@ public class LoanRepaymentBusinessEventSerializerTest {
AvroRuntimeException exceptionThrown = assertThrows(AvroRuntimeException.class, () -> serializer.toAvroDTO(event));
assertTrue(exceptionThrown.getMessage().contains("does not accept null values"));
}
}
@@ -56,6 +56,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -99,6 +100,11 @@ class LoanCOBApiFilterTest {
testObj = new LoanCOBApiFilter(helper);
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
void shouldLoanAndExternalMatchToo() {
String externalId = UUID.randomUUID().toString();
@@ -45,6 +45,7 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.investor.enricher.LoanAccountDataV1Enricher;
import org.apache.fineract.investor.enricher.LoanChargeDataV1Enricher;
import org.apache.fineract.investor.enricher.LoanTransactionDataV1Enricher;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -66,6 +67,11 @@ public class EnricherTest {
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void testLoanAccountDataEnricher() {
LoanAccountDataV1Enricher loanAccountDataV1Enricher = mock(LoanAccountDataV1Enricher.class);
@@ -178,5 +184,4 @@ public class EnricherTest {
assertEquals(PURCHASE_PRICE_RATIO, data.getPurchasePriceRatio());
}
}
@@ -76,6 +76,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleIns
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -130,6 +131,11 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void givenLoanAccountWithDelinquencyBucketWhenRangeChangeThenEventIsRaised() {
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDeliquencyRangeChangeEvent = ArgumentCaptor
@@ -614,5 +620,4 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
Loan loanPayloadForEvent = loanDelinquencyRangeChangeEvent.getValue().get();
assertEquals(loanForProcessing, loanPayloadForEvent);
}
}
@@ -105,6 +105,7 @@ public class LoanDelinquencyDomainServiceTest {
@AfterEach
public void deregister() {
ThreadLocalContextUtil.reset();
moneyHelperStatic.close();
}
@@ -27,16 +27,23 @@ import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;
@@ -46,11 +53,21 @@ import org.springframework.test.util.ReflectionTestUtils;
*/
public class LoanTest {
private final LocalDate actualDate = LocalDate.now(ZoneId.systemDefault());
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
/**
* Tests {@link Loan#getCharges()} with charges.
*/
@Test
public void testGetChargesWithCharges() {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate)));
Loan loan = new Loan();
ReflectionTestUtils.setField(loan, "charges", Collections.singleton(buildLoanCharge()));
@@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTransactionType;
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -83,6 +84,11 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, transactionDate)));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
@Test
public void chargePaymentTransactionTestWithExactAmount() {
final BigDecimal chargeAmount = BigDecimal.valueOf(100);
@@ -44,6 +44,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleIns
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -104,6 +105,11 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, transactionDate)));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
// IN ADVANCE
@Test
public void inAdvancePaymentOfPrincipal() {
@@ -44,6 +44,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleIns
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -105,6 +106,11 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, transactionDate)));
}
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
}
// IN ADVANCE
@Test
public void inAdvancePaymentOfPrincipal() {
@@ -69,6 +69,7 @@ public class LoanCalculateRepaymentPastDueServiceTest {
@AfterEach
public void reset() {
ThreadLocalContextUtil.reset();
moneyHelper.close();
}