Unit testing CompletableFutures, Junit, Mockito, #RunWith(SpringRunner.class) - spring-boot

I need help testing this CF's.
public class RateHandler {
public Response firstMethod(RateRequest, Context context) {
CompletableFuture<Response> rateRespCf = CompletableFuture.supplyAsync(() -> {
try {
return firstHandler.handle(rateRequest, context);
} catch (Exception e) {
throw new RuntimeException(e);
}
}, executorService);
// same here as well rateRespCf is not taking the stubbed value from the test
//hence resulting null
CompletableFuture<Double> avgRateCf =
CompletableFuture.supplyAsync(() ->
secondHandler.handle(rateRequest, context), executorService);
//avgRateCf is coming with 0.0 value though I'm stubbing it with 1.2 from the test.
//I looked inside the mockInterceptor in debug mode I see 1.2 under stubbed section
//but by the time it completes executing the line it gives me 0.0
CompletableFuture<Response> result = rateRespCf //'rateRespCf' this is NULL as well
.thenCompose(rateResp -> CompletableFuture.supplyAsync(() ->
secondMethod(rateResp, avgRateCf), executorService));
return result.get(); //getting NPE here when running the test
}
private RateResponse secondMethod(RateResponse rateResponse, CompletableFuture<Double> avgRateCf) {
// some business logic
for(Rate: rateResponse.getRates()) { //getting NPE at this line also when running the test since rateResponse is null
rate.setValue(avgRateCf.get())
}
return rateResponse;
}
}
I added my test case like this but I'm getting NPE by the time the control reached result.get not sure why result is coming as NULL as you can see in the test from this line when(rateHandler.handler(getRateLookupRequest(),context)).thenReturn(rateLookupResponse); it should return the value in thenReturn. In fact none of the thenReturn are working everything is coming as null. Please help.
//MyTest
#Mock
FirstHandler firstHandler;
#Mock
SecondHandler secondHandler;
#InjectMocks
RateHandler rateHandler;
#Test
public void testRateHandler()
throws BusinessException, IOException, ExecutionException, InterruptedException {
when(firstHandler.handle(rateRequest(), context)).thenReturn(rateResponse);
when(secondHandler.handle(rateRequest(), context))).thenReturn(1.2);
when(rateHandler.handler(getRateLookupRequest(),context)).thenReturn(rateLookupResponse);
}
I even tried this approach still no luck
#Test
public void testRateHandler1()
throws BusinessException, IOException, ExecutionException, InterruptedException {
CompletableFuture<RateLookupResponse> rateLookupResponseCf = CompletableFuture.completedFuture(rateLookupResponse);
CompletableFuture<Double> doubleCf = CompletableFuture.completedFuture(1.2);
doReturn(rateLookupResponseCf)
.when(firstHandler)
.handle(getRateLookupRequest(), context);
doReturn(doubleCf)
.when(secondHandler)
.handle(getRateLookupRequest(), context);
RateLookupResponse response = rateHandler.handler(getRateLookupRequest(), context);
assertNotNull(response);
}
PS: firstHandler.handle(rateRequest(), context) //returns and POJO
secondHandler.handle(rateRequest(), context) // returns primitive double
rateHandler.handle(rateRequest(), context) //returns POJO

Related

How to accept http requests after shutdown signal in Quarkus?

I tried this:
void onShutdown(#Observes final ShutdownEvent event) throws InterruptedException {
log.infof("ShutdownEvent received, waiting for %s seconds before shutting down", shutdownWaitSeconds);
TimeUnit.SECONDS.sleep(shutdownWaitSeconds);
log.info("Continue shutting down");
}
But after receiving ShutdownEvent Quarkus already responds with 503 to http requests. Looks like this could be done with ShutdownListener in preShutdown method. I have implemented this listener but it does not get called yet. How do I register ShutdownListener?
Use case here is OpenShift sending requests to terminating pod.
Option 1: Create Quarkus extension
Instructions are here. ShutdownController is my own class implementing ShutdownListener where I have a sleep in preShutdown method.
class ShutdownControllerProcessor {
#BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem("shutdown-controller");
}
#BuildStep
ShutdownListenerBuildItem shutdownListener() {
// Called at build time. Default constructor will be called at runtime.
// Getting MethodNotFoundException when calling default constructor here.
return new ShutdownListenerBuildItem(new ShutdownController(10));
}
}
Option 2: Modify ShutdownRecorder private static final field
New shutdown listener can be added using reflection. This is a bit ugly solution.
registerIfNeeded() need to be called after Quarkus startup, for example with timer 1 second after #PostConstruct.
#ApplicationScoped
public class ListenerRegisterer {
public void registerIfNeeded() {
try {
tryToRegister();
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
private void tryToRegister() throws NoSuchFieldException, IllegalAccessException {
final var field = ShutdownRecorder.class.getDeclaredField("shutdownListeners");
field.setAccessible(true);
final var listeners = (List<ShutdownListener>) field.get(null);
if (listeners != null && !listeners.toString().contains("ShutdownController")) {
listeners.add(new ShutdownController(10));
setFinalStatic(field, listeners);
}
}
private static void setFinalStatic(final Field field, final Object newValue) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
final var modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
}

Unit testing GatewayFilter causes NullPointerException

I'm trying to unit test my GatewayFilter, however I'm having troubles running even simple test.
This is small example of what is failing right now
#ExtendWith(MockitoExtension.class)
public class SomeFilterTest {
private final GatewayFilter gatewayFilter = (exchange, chain) ->
Mono.just("Hello")
.flatMap(this::doSomething)
.switchIfEmpty(Mono.defer(() -> chain.filter(exchange)));
private Mono<Void> doSomething(String value) {
System.out.println(value);
return Mono.empty();
}
#Test
void test1() {
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());
var chain = mock(GatewayFilterChain.class);
gatewayFilter.filter(exchange, chain).block();
}
}
Unfortunatelly, it is failing because of
The Mono returned by the supplier is null
java.lang.NullPointerException: The Mono returned by the supplier is
null at java.base/java.util.Objects.requireNonNull(Objects.java:246)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) at
reactor.core.publisher.Mono.subscribe(Mono.java:4361)
And to be honest, I have no idea why is that happening?
You have not stubbed out the filter method call on your mock object, GatewayFilterChain. As a result, the supplier () -> chain.filter(exchange) returns null. You are not allowed to create a Mono with a value of null, hence the exception.
As a result your test should look something like
#Test
public void test1() {
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());
var chain = mock(WebFilterChain.class);
// stubbing behaviour on our mock object
given(chain.filter(exchange)).willReturn(Mono.empty());
gatewayFilter.filter(exchange, chain).block();
}
Additionally, I would suggest using StepVerifier instead of using block() in unit tests. This is provided by reactor-test and is purpose built for unit testing reactive code
#Test
public void test1() {
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());
var chain = mock(WebFilterChain.class);
given(chain.filter(exchange)).willReturn(Mono.empty());
StepVerifier.create(gatewayFilter.filter(exchange, chain))
.verifyComplete();
}
Here is a very useful Step Verifier Tutorial to help you get started

Why isnt Mockito doThrow throwing an Exception in this case? zero interactions with mock

method I am testing (the method setEventHubDataPayload throws JSONException and JsonProcessingException):
public class EventHubMapper {
//inits
public byte[] toEventDataJsonByteArray(UserRecord inbound) {
EventHubDto ehDto = new EventHubDto();
ehDto.setEventTypeVersion(inbound.getVersion());
ehDto.setEventId(inbound.getNotificationId());
JSONObject eventJson = new JSONObject(ehDto);
try {
eventJson.put("data", setEventHubDataPayload(ehDto, inbound));
} catch (JSONException e) {
analytics.trackError(AnalyticsConstants.EventHub.JSON_MAPPING_ERROR, e.toString());
} catch (JsonProcessingException e) {
analytics.trackError(AnalyticsConstants.EventHub.JSON_PROCESSING_ERROR, e.toString());
}
return eventJson.toString().getBytes();
}
}
unit test code:
#Test
public void toEventDataByteArray_JsonException() throws JSONException, JsonProcessingException {
EventHubMapper ehmMock = Mockito.spy(eventHubMapper);
doThrow(new JSONException("blah")).when(ehmMock).setEventHubDataPayload(any(), any());
eventHubMapper.toEventDataJsonByteArray(setUpMockUserRecord());
verify(analytics, times(1)).trackError( AnalyticsConstants.EventHub.JSON_MAPPING_ERROR, new JSONException("blah").toString());
}
I've tried using more specific matchers ... ex: any(EventHubDto.class) or any(UserRecord.class) and got the same result:
Wanted but not invoked:
analytics.trackError(
"EventHub_Publish_Error",
""
;
and also
Actually, there were zero interactions with this mock.
what is going on here?
I think you need to call like below while testing.
ehmMock.toEventDataJsonByteArray(setUpMockUserRecord());

Spring #Async with CompletableFuture

I have a doubt about this code:
#Async
public CompletableFuture<String> doFoo() {
CompletableFuture<String> fooFuture = new CompletableFuture<>();
try {
String fooResult = longOp();
fooFuture.complete(fooResult);
} catch (Exception e) {
fooFuture.completeExceptionally(e);
}
return fooFuture;
}
The question is: does doFoo return fooFuture only after longOp has finished (either correctly or exceptionally) and is therefore returning already completed futures or is Spring doing some magic and returning before executing the body? If the code is blocking on longOp(), how would you express that the computation is being fed to an executor?
Perhaps this? Any other way?
#Async
public CompletableFuture<String> doFoo() {
CompletableFuture<String> completableFuture = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
try {
String fooResult = longOp();
completableFuture.complete(fooResult);
} catch (Exception e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
Spring actually does all of the work behind the covers so you don't have to create the CompletableFuture yourself.
Basically, adding the #Async annotation is as if you called your original method (without the annotation) like:
CompletableFuture<User> future = CompletableFuture.runAsync(() -> doFoo());
As for your second question, in order to feed it to an executor, you can specify the exectutor bean name in the value of the #Async annotation, like so:
#Async("myExecutor")
public CompletableFuture<User> findUser(String usernameString) throws InterruptedException {
User fooResult = longOp(usernameString);
return CompletableFuture.completedFuture(fooResult);
}
The above would basically be the following as if you called your original method, like:
CompletableFuture<User> future = CompletableFuture.runAsync(() -> doFoo(), myExecutor);
And all of your exceptionally logic you would do with the returned CompletableFuture from that method.

Spring #Async with Future and Callable

I am trying to implement a generic class that executes a callable asynchronously, but I am not sure about the semantics.
#Component
public class MyCallerImpl implements MyCaller {
#Async
#Override
public <T> Future<T> runAsync(Callable<T> callable) throws Exception {
return new AsyncResult<T>(callable.call());
}
}
Basically, this component executes arbitrary actions from any callable asynchronously using the #Async annotation.
I am unsure about the Exception in the throws clause of the method signature.
A Junit test:
#ContextConfiguration("classpath:test-config.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class RunnerTest{
#Resource(name="myCallerImpl")
private MyCaller myCaller;
#Test
public void testException(){
final Callable<String> callable = new Callable<String>(){
#Override
public String call() throws Exception{
throw new MyException("foobar");
}
};
try
{
final Future<String> future = myCaller.runAsync(callable); // this can throw Exception due to Callable.call()
future.get(); // this can throw InterruptedException and ExecutionException
}
catch (final InterruptedException ie)
{
// do someting
}
catch (final ExecutionException ee)
{
// we want to check the cause
final Throwable cause = ee.getCause();
assertTrue(cause instanceof MyException);
}
catch (final Exception e)
{
// Not sure what to do here.
// Must be caught as it is declared to
// be thrown from the MyCaller.runAsync() method
// but nothing will really ever get here
// since the method is #Async and any exception will be
// wrapped by an ExecutionException and thrown during Future.get()
fail("this is unexpected);
}
My question is what to do about the Exception declared in the throws clause of MyCallerImpl.runAsync()?
The only reason I have declared it is because of the way I am calling the callable. Originally I had the following in the async method:
FutureTask<T> futureTask = new FutureTask<T>(callable);
futureTask.run();
return futureTask;
But when an exception is thrown from the callable in that instance, it gets wrapped twice in an ExecutionException, the first time when FutureTask.run() is called eventually FutureTask.Sync.innerRun() catches the exception and calls innnerSetException() and a second time when the AsyncExecutionIntercepter gets the result from the Future via Future.get(), which eventually again checks if there is an exception and throws a new ExecutionException wrapping the ExecutionException caught in innerRun()
I also tried to do the following in the method:
FutureTask<T> futureTask = new FutureTask<T>(callable);
return futureTask;
I had figured that since the AsyncExecutionInterceptor calls Future.get(), that the callable would be called immediately, but that was not the case. It just hangs on FutureTask.acquireSharedInterruptibly() and never returns.
Maybe I'm in over my head here. It works how I have it set-up with the callable now, but I rather not have the method signature declare a throws Exception.
Any advice? Should I forget about this generic way of doing async calls with a callable?
There are 2 layers of exception here.
one:
the exception leading to the calling of the Callable
if (string.equals("X")){ callable.call();}
two:
the exception caused when calling the callable.call() method (your "throw new MyException("foobar");")
since you do not have any other code prior to "callable.call();", it would be safe to remove the checked exception.
Change
public <T> Future<T> runAsync(Callable<T> callable) throws Exception
to
public <T> Future<T> runAsync(Callable<T> callable)
additionally, you can code it this way
final Future<String> future = myCaller.runAsync(callable);
try
{
future.get(); // this can throw InterruptedException and ExecutionException
}
catch (final InterruptedException ie)
{
// do someting
}
catch (final ExecutionException ee)
{
// we want to check the cause
final Throwable cause = ee.getCause();
assertTrue(cause instanceof MyException);
}

Resources