FINERACT-1760: Raise transaction replayed business event

This commit is contained in:
Adam Saghy
2022-11-29 10:04:22 +01:00
committed by Arnold Gálovics
parent bbd1ca75a1
commit 4c597b61fb
13 changed files with 310 additions and 52 deletions
@@ -51,20 +51,27 @@ public class COBBusinessStepServiceImpl implements COBBusinessStepService {
if (executionMap == null || executionMap.isEmpty()) {
throw new BusinessStepException("Execution map is empty! COB Business step execution skipped!");
}
businessEventNotifierService.startExternalEventRecording();
for (String businessStep : executionMap.values()) {
try {
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
COBBusinessStep<S> businessStepBean = (COBBusinessStep<S>) applicationContext.getBean(businessStep);
item = businessStepBean.execute(item);
} catch (Exception e) {
throw new BusinessStepException("Error happened during business step execution", e);
} finally {
// Fallback to COB action context after each business step
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
// Extra safety net to avoid event leaking
try {
businessEventNotifierService.startExternalEventRecording();
for (String businessStep : executionMap.values()) {
try {
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
COBBusinessStep<S> businessStepBean = (COBBusinessStep<S>) applicationContext.getBean(businessStep);
item = businessStepBean.execute(item);
} catch (Exception e) {
throw new BusinessStepException("Error happened during business step execution", e);
} finally {
// Fallback to COB action context after each business step
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
}
}
businessEventNotifierService.stopExternalEventRecording();
} catch (Exception e) {
businessEventNotifierService.resetEventRecording();
throw e;
}
businessEventNotifierService.stopExternalEventRecording();
return item;
}
@@ -50,4 +50,6 @@ public interface BusinessEventNotifierService {
void startExternalEventRecording();
void stopExternalEventRecording();
void resetEventRecording();
}
@@ -155,4 +155,10 @@ public class BusinessEventNotifierServiceImpl implements BusinessEventNotifierSe
recordedEvents.remove();
}
}
@Override
public void resetEventRecording() {
eventRecordingEnabled.set(false);
recordedEvents.remove();
}
}
@@ -91,6 +91,7 @@ import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.portfolio.loanaccount.service.ReplayedTransactionBusinessEventService;
import org.apache.fineract.portfolio.note.domain.Note;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
@@ -127,6 +128,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private final DelinquencyWritePlatformService delinquencyWritePlatformService;
private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
private final ExternalIdFactory externalIdFactory;
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
@Transactional
@Override
@@ -210,11 +212,14 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
if (changedTransactionDetail != null) {
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
saveLoanTransactionWithDataIntegrityViolationChecks(mapEntry.getValue());
// update loan with references to the newly created transactions
loan.addLoanTransaction(mapEntry.getValue());
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
if (StringUtils.isNotBlank(noteText)) {
@@ -788,6 +793,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
loan.getLoanTransactions().add(mapEntry.getValue());
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
@@ -30,6 +30,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
@@ -78,10 +79,10 @@ import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanResch
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.portfolio.loanaccount.service.ReplayedTransactionBusinessEventService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.orm.jpa.JpaSystemException;
@@ -89,6 +90,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanRescheduleRequestWritePlatformService {
private static final Logger LOG = LoggerFactory.getLogger(LoanRescheduleRequestWritePlatformServiceImpl.class);
@@ -111,45 +113,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
private static final DefaultScheduledDateGenerator DEFAULT_SCHEDULED_DATE_GENERATOR = new DefaultScheduledDateGenerator();
private final LoanAccountDomainService loanAccountDomainService;
private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
/**
* LoanRescheduleRequestWritePlatformServiceImpl constructor
*
*
**/
@Autowired
public LoanRescheduleRequestWritePlatformServiceImpl(final CodeValueRepositoryWrapper codeValueRepositoryWrapper,
final PlatformSecurityContext platformSecurityContext,
final LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator,
final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository,
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
final LoanTransactionRepository loanTransactionRepository,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanRepositoryWrapper loanRepositoryWrapper,
final LoanAssembler loanAssembler, final LoanUtilService loanUtilService,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final LoanScheduleGeneratorFactory loanScheduleFactory, final LoanSummaryWrapper loanSummaryWrapper,
final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
final LoanAccountDomainService loanAccountDomainService,
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository) {
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
this.platformSecurityContext = platformSecurityContext;
this.loanRescheduleRequestDataValidator = loanRescheduleRequestDataValidator;
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
this.loanRepaymentScheduleHistoryRepository = loanRepaymentScheduleHistoryRepository;
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
this.loanTransactionRepository = loanTransactionRepository;
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
this.loanRepositoryWrapper = loanRepositoryWrapper;
this.loanAssembler = loanAssembler;
this.loanUtilService = loanUtilService;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.loanScheduleFactory = loanScheduleFactory;
this.loanSummaryWrapper = loanSummaryWrapper;
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
this.loanAccountDomainService = loanAccountDomainService;
this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
}
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
/**
* create a new instance of the LoanRescheduleRequest object from the JsonCommand object and persist
@@ -490,6 +454,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
loan.addLoanTransaction(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
@@ -155,6 +155,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
private final ExternalIdFactory externalIdFactory;
private final AccountTransferDetailRepository accountTransferDetailRepository;
private final LoanChargeAssembler loanChargeAssembler;
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) {
return e.getFromDate().isBefore(loanCharge.getDueDate()) && !loanCharge.getDueDate().isAfter(e.getDueDate());
@@ -246,6 +247,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
loan.addLoanTransaction(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
this.loanRepositoryWrapper.save(loan);
}
@@ -740,6 +743,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
loan.addLoanTransaction(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
}
@@ -1085,6 +1090,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
loan.addLoanTransaction(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
}
}
@@ -241,6 +241,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
private final LoanAccountLockService loanAccountLockService;
private final ExternalIdFactory externalIdFactory;
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
@Transactional
@Override
@@ -457,6 +458,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanTransactionRepository.save(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
// auto create standing instruction
@@ -732,6 +735,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanTransactionRepository.save(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
@@ -1129,6 +1134,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.addLoanTransaction(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
final String noteText = command.stringValueOfParameterNamed("note");
@@ -1360,6 +1367,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.addLoanTransaction(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
final String noteText = command.stringValueOfParameterNamed("note");
@@ -2128,6 +2137,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanTransactionRepository.save(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
saveLoanWithDataIntegrityViolationChecks(loan);
@@ -2268,8 +2279,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (command.entityId() != null && changedTransactionDetail != null) {
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
this.loanTransactionRepository.save(mapEntry.getValue());
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
createLoanScheduleArchive(loan, scheduleGeneratorDTO);
@@ -2326,6 +2340,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.addLoanTransaction(mapEntry.getValue());
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
// Trigger transaction replayed event
replayedTransactionBusinessEventService.raiseTransactionReplayedEvents(changedTransactionDetail);
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
loanAccountDomainService.recalculateAccruals(loan);
@@ -0,0 +1,26 @@
/**
* 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.portfolio.loanaccount.service;
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
public interface ReplayedTransactionBusinessEventService {
void raiseTransactionReplayedEvents(ChangedTransactionDetail changedTransactionDetail);
}
@@ -0,0 +1,59 @@
/**
* 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.portfolio.loanaccount.service;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class ReplayedTransactionBusinessEventServiceImpl implements ReplayedTransactionBusinessEventService {
private final BusinessEventNotifierService businessEventNotifierService;
private final LoanTransactionRepository loanTransactionRepository;
@Override
public void raiseTransactionReplayedEvents(final ChangedTransactionDetail changedTransactionDetail) {
if (changedTransactionDetail == null || changedTransactionDetail.getNewTransactionMappings().isEmpty()) {
return;
}
// Extra safety net to avoid event leaking
try {
businessEventNotifierService.startExternalEventRecording();
for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
LoanTransaction oldTransaction = loanTransactionRepository.findById(mapEntry.getKey())
.orElseThrow(() -> new LoanTransactionNotFoundException(mapEntry.getKey()));
LoanAdjustTransactionBusinessEvent.Data data = new LoanAdjustTransactionBusinessEvent.Data(oldTransaction);
data.setNewTransactionDetail(mapEntry.getValue());
businessEventNotifierService.notifyPostBusinessEvent(new LoanAdjustTransactionBusinessEvent(data));
}
businessEventNotifierService.stopExternalEventRecording();
} catch (Exception e) {
businessEventNotifierService.resetEventRecording();
throw e;
}
}
}
@@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import com.google.common.base.Splitter;
import io.cucumber.java8.En;
@@ -39,6 +40,7 @@ import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.mix.data.MixTaxonomyData;
import org.mockito.Mockito;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
@@ -147,6 +149,14 @@ public class COBBusinessStepServiceStepDefinitions implements En {
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
});
Then("throw exception COBBusinessStepService.run method with verification", () -> {
assertThrows(BusinessStepException.class, () -> {
resultItem = this.businessStepService.run(this.executionMap, this.item);
});
verify(businessEventNotifierService, Mockito.times(1)).resetEventRecording();
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
});
Then("The COBBusinessStepService.getCOBBusinessStepMap result exception", () -> {
assertThrows(BeanCreationException.class, () -> {
this.businessStepService.getCOBBusinessStepMap(this.clazz, this.jobName);
@@ -24,6 +24,8 @@ import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import io.cucumber.java8.En;
import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
import org.springframework.batch.repeat.RepeatStatus;
@@ -56,12 +58,14 @@ public class InitialisationTaskletStepDefinitions implements En {
Then("InitialisationTasklet.execute result should match", () -> {
assertEquals(RepeatStatus.FINISHED, resultItem);
assertEquals(appUser, SecurityContextHolder.getContext().getAuthentication().getPrincipal());
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
});
Then("throw exception InitialisationTasklet.execute method", () -> {
assertThrows(RuntimeException.class, () -> {
resultItem = this.initialisationTasklet.execute(null, null);
});
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
});
}
}
@@ -0,0 +1,140 @@
/**
* 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.portfolio.loanaccount.service;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.verify;
import java.util.Optional;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class ReplayedTransactionBusinessEventServiceIntegrationTest {
@Mock
private BusinessEventNotifierService businessEventNotifierService;
@Mock
private LoanTransactionRepository loanTransactionRepository;
private ReplayedTransactionBusinessEventService underTest;
@BeforeEach
public void setUp() {
underTest = new ReplayedTransactionBusinessEventServiceImpl(businessEventNotifierService, loanTransactionRepository);
}
@Test
public void testWhenParamIsNull() {
// given
ChangedTransactionDetail changedTransactionDetail = null;
// when
underTest.raiseTransactionReplayedEvents(changedTransactionDetail);
// then
verify(businessEventNotifierService, Mockito.times(0)).startExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(0))
.notifyPostBusinessEvent(Mockito.any(LoanAdjustTransactionBusinessEvent.class));
verify(businessEventNotifierService, Mockito.times(0)).stopExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(0)).resetEventRecording();
}
@Test
public void testWhenParamHasNoMapping() {
// given
ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
// when
underTest.raiseTransactionReplayedEvents(changedTransactionDetail);
// then
verify(businessEventNotifierService, Mockito.times(0)).startExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(0))
.notifyPostBusinessEvent(Mockito.any(LoanAdjustTransactionBusinessEvent.class));
verify(businessEventNotifierService, Mockito.times(0)).stopExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(0)).resetEventRecording();
}
@Test
public void testWhenParamHasOneNewTransaction() {
// given
LoanTransaction oldLoanTransaction = Mockito.mock(LoanTransaction.class);
LoanTransaction newLoanTransaction = Mockito.mock(LoanTransaction.class);
lenient().when(loanTransactionRepository.findById(1L)).thenReturn(Optional.of(oldLoanTransaction));
ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
changedTransactionDetail.getNewTransactionMappings().put(1L, newLoanTransaction);
// when
underTest.raiseTransactionReplayedEvents(changedTransactionDetail);
// then
verify(businessEventNotifierService, Mockito.times(1)).startExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(1))
.notifyPostBusinessEvent(Mockito.any(LoanAdjustTransactionBusinessEvent.class));
verify(businessEventNotifierService, Mockito.times(1)).stopExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(0)).resetEventRecording();
}
@Test
public void testWhenParamHasTwoNewTransaction() {
// given
LoanTransaction oldLoanTransaction = Mockito.mock(LoanTransaction.class);
LoanTransaction newLoanTransaction = Mockito.mock(LoanTransaction.class);
lenient().when(loanTransactionRepository.findById(1L)).thenReturn(Optional.of(oldLoanTransaction));
lenient().when(loanTransactionRepository.findById(2L)).thenReturn(Optional.of(oldLoanTransaction));
ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
changedTransactionDetail.getNewTransactionMappings().put(1L, newLoanTransaction);
changedTransactionDetail.getNewTransactionMappings().put(2L, newLoanTransaction);
// when
underTest.raiseTransactionReplayedEvents(changedTransactionDetail);
// then
verify(businessEventNotifierService, Mockito.times(1)).startExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(2))
.notifyPostBusinessEvent(Mockito.any(LoanAdjustTransactionBusinessEvent.class));
verify(businessEventNotifierService, Mockito.times(1)).stopExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(0)).resetEventRecording();
}
@Test
public void testWhenParamHasError() {
// given
doThrow(new RuntimeException()).when(businessEventNotifierService)
.notifyPostBusinessEvent(Mockito.any(LoanAdjustTransactionBusinessEvent.class));
LoanTransaction oldLoanTransaction = Mockito.mock(LoanTransaction.class);
LoanTransaction newLoanTransaction = Mockito.mock(LoanTransaction.class);
lenient().when(loanTransactionRepository.findById(1L)).thenReturn(Optional.of(oldLoanTransaction));
ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
changedTransactionDetail.getNewTransactionMappings().put(1L, newLoanTransaction);
// when
assertThrows(RuntimeException.class, () -> underTest.raiseTransactionReplayedEvents(changedTransactionDetail));
// then
verify(businessEventNotifierService, Mockito.times(1)).startExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(1))
.notifyPostBusinessEvent(Mockito.any(LoanAdjustTransactionBusinessEvent.class));
verify(businessEventNotifierService, Mockito.times(0)).stopExternalEventRecording();
verify(businessEventNotifierService, Mockito.times(1)).resetEventRecording();
}
}
@@ -37,6 +37,14 @@ Feature: COB
Examples:
|executionMap|
|null|
@cob
Scenario Outline: COB Business Step Service - run test failure
Given The COBBusinessStepService.run method with executeMap <executionMap>
Then throw exception COBBusinessStepService.run method with verification
Examples:
|executionMap|
|2,notExist|
|3,|