FINERACT-1927: Incorrect exception info in BatchAPI response

This commit is contained in:
jmarta
2023-09-27 19:13:26 +02:00
committed by Adam Saghy
parent f452ce2cad
commit 32da7db35d
55 changed files with 1399 additions and 1134 deletions
@@ -20,6 +20,7 @@ package org.apache.fineract.commands.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import io.cucumber.java8.En;
import io.github.resilience4j.retry.RetryRegistry;
@@ -33,11 +34,14 @@ import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.exception.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.test.util.ReflectionTestUtils;
public class CommandServiceStepDefinitions implements En {
@@ -55,16 +59,24 @@ public class CommandServiceStepDefinitions implements En {
private RetryEvent retryEvent;
private AtomicInteger counter = new AtomicInteger();
public CommandServiceStepDefinitions() {
Given("/^A command source write service$/", () -> {
this.commandSourceWritePlatformService = new DummyCommandSourceWriteService(processAndLogCommandService);
this.command = new DummyCommand();
FineractRequestContextHolder contextHolder = Mockito.spy(FineractRequestContextHolder.class);
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()));
this.retryRegistry.retry("executeCommand").getEventPublisher().onRetry(event -> {
log.warn("... retry event: {}", event);
counter.incrementAndGet();
CommandServiceStepDefinitions.this.retryEvent = event;
});
});
When("/^The user executes the command via a command write service with exceptions$/", () -> {
@@ -84,47 +96,21 @@ public class CommandServiceStepDefinitions implements En {
});
Then("/^The command processing service execute function should be called 3 times$/", () -> {
assertEquals(3, command.getCount());
assertEquals(2, counter.get());
});
}
public static class DummyCommand extends CommandWrapper {
private AtomicInteger counter = new AtomicInteger();
public DummyCommand() {
super(null, null, null, null, null, null, null, null, null, null, "{}", null, null, null, null, null, null,
UUID.randomUUID().toString());
}
@Override
public String taskPermissionName() {
// NOTE: simulating a failure scenario that triggers retries; using this function, because it is the first
// called in the command processing service
int step = counter.incrementAndGet();
log.warn("Round: {}", step);
if (step == 1) {
throw new CannotAcquireLockException("BLOW IT UP!!!");
} else if (step == 2) {
throw new ObjectOptimisticLockingFailureException("Dummy", new RuntimeException("BLOW IT UP!!!"));
} else if (step == 3) {
throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(new DummyCommandSource());
}
return "dummy";
}
@Override
public String actionName() {
return "dummy";
}
public int getCount() {
return counter.get();
}
}
public static class DummyCommandSourceWriteService implements PortfolioCommandSourceWritePlatformService {
@@ -74,7 +74,7 @@ public class CommandSourceServiceTest {
ThreadLocalContextUtil.setTenant(ft);
String idk = "idk";
underTest.saveInitial(wrapper, jsonCommand, appUser, idk);
underTest.saveInitialNewTransaction(wrapper, jsonCommand, appUser, idk);
ArgumentCaptor<CommandSource> commandSourceArgumentCaptor = ArgumentCaptor.forClass(CommandSource.class);
Mockito.verify(commandSourceRepository).saveAndFlush(commandSourceArgumentCaptor.capture());
@@ -97,7 +97,7 @@ public class CommandSourceServiceTest {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "t1", "n1", ZoneId.systemDefault().toString(), null));
CommandSource actual = underTest.saveInitial(wrapper, jsonCommand, appUser, "idk");
CommandSource actual = underTest.saveInitialNewTransaction(wrapper, jsonCommand, appUser, "idk");
ArgumentCaptor<CommandSource> commandSourceArgumentCaptor = ArgumentCaptor.forClass(CommandSource.class);
Mockito.verify(commandSourceRepository).saveAndFlush(commandSourceArgumentCaptor.capture());
@@ -108,9 +108,10 @@ public class CommandSourceServiceTest {
@Test
public void testGenerateErrorException() {
Mockito.when(errorHandler.getMappable(any())).thenAnswer(i -> i.getArguments()[0]);
Mockito.when(errorHandler.handle(any(CodeNotFoundException.class)))
.thenReturn(new ErrorInfo(404, 1001, "Code with name `foo` does not exist"));
ErrorInfo result = underTest.generateErrorException(new CodeNotFoundException("foo"));
.thenReturn(new ErrorInfo(404, 1001, "Code with name `foo` does not exist", null));
ErrorInfo result = underTest.generateErrorInfo(new CodeNotFoundException("foo"));
Assertions.assertEquals(404, result.getStatusCode());
Assertions.assertEquals(1001, result.getErrorCode());
Assertions.assertTrue(result.getMessage().contains("Code with name `foo` does not exist"));
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.commands.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -85,7 +86,6 @@ public class SynchronousCommandProcessingServiceTest {
@Test
public void testExecuteCommandSuccess() {
CommandWrapper commandWrapper = Mockito.mock(CommandWrapper.class);
when(commandWrapper.isDatatableResource()).thenReturn(false);
when(commandWrapper.isNoteResource()).thenReturn(false);
@@ -103,19 +103,24 @@ public class SynchronousCommandProcessingServiceTest {
String idk = "idk";
when(idempotencyKeyResolver.resolve(commandWrapper)).thenReturn(idk);
CommandSource commandSource = Mockito.mock(CommandSource.class);
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null).thenReturn(commandSource);
long commandId = 1L;
when(commandSource.getId()).thenReturn(commandId);
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(null);
when(commandSourceService.getCommandSource(commandId)).thenReturn(commandSource);
AppUser appUser = Mockito.mock(AppUser.class);
when(commandSourceService.saveInitial(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
when(commandSourceService.saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
when(commandSourceService.saveResultSameTransaction(commandSource)).thenReturn(commandSource);
when(commandSource.getStatus()).thenReturn(CommandProcessingResultType.PROCESSED.getValue());
when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser);
CommandProcessingResult actualCommandProcessingResult = underTest.executeCommand(commandWrapper, jsonCommand, false);
verify(commandSourceService).saveInitial(commandWrapper, jsonCommand, appUser, idk);
verify(commandSource).setStatus(CommandProcessingResultType.PROCESSED.getValue());
verify(commandSourceService).saveResult(commandSource);
verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk);
assertEquals(CommandProcessingResultType.PROCESSED.getValue(), commandSource.getStatus());
verify(commandSourceService).saveResultSameTransaction(commandSource);
Assertions.assertEquals(commandProcessingResult, actualCommandProcessingResult);
assertEquals(commandProcessingResult, actualCommandProcessingResult);
}
@Test
@@ -142,7 +147,7 @@ public class SynchronousCommandProcessingServiceTest {
AppUser appUser = Mockito.mock(AppUser.class);
when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser);
when(commandSourceService.saveInitial(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
when(commandSourceService.saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk)).thenReturn(commandSource);
CommandSource initialCommandSource = Mockito.mock(CommandSource.class);
@@ -152,7 +157,7 @@ public class SynchronousCommandProcessingServiceTest {
underTest.executeCommand(commandWrapper, jsonCommand, false);
});
verify(commandSourceService).saveInitial(commandWrapper, jsonCommand, appUser, idk);
verify(commandSourceService).generateErrorException(runtimeException);
verify(commandSourceService).saveInitialNewTransaction(commandWrapper, jsonCommand, appUser, idk);
verify(commandSourceService).generateErrorInfo(runtimeException);
}
}
@@ -47,7 +47,7 @@ public class InvalidInstanceTypeMethodExceptionMapperTest {
assertEquals(Response.Status.METHOD_NOT_ALLOWED.getStatusCode(), response.getStatus());
assertNotNull(response.getEntity());
final ApiGlobalErrorResponse errorResponse = (ApiGlobalErrorResponse) response.getEntity();
assertEquals(String.valueOf(Response.Status.METHOD_NOT_ALLOWED.getReasonPhrase()), errorResponse.getHttpStatusCode());
assertEquals(String.valueOf(Response.Status.METHOD_NOT_ALLOWED.getStatusCode()), errorResponse.getHttpStatusCode());
assertEquals("Invalid instance type called in api request for the method POST", errorResponse.getDeveloperMessage());
assertEquals("error.msg.invalid.instance.type", errorResponse.getUserMessageGlobalisationCode());
assertEquals("Invalid method POST used with request to this instance type.", errorResponse.getDefaultUserMessage());