From 99289331802a18f87d1a1c1db22a714cb9509191 Mon Sep 17 00:00:00 2001 From: HARPER Jon Date: Mon, 23 Jan 2023 16:07:39 +0100 Subject: [PATCH] Fix block() not supported exception in tests By chance, the exception didn't hinder the tests but it could so fix it in SecurityAnalysisControllerTest#runAndSaveTest 15:51:19.038 [parallel-8] ERROR org.gridsuite.securityanalysis.server.service.SecurityAnalysisWorkerService - Exception in consumeRun java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread parallel-8 at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83) at reactor.core.publisher.Mono.block(Mono.java:1707) at org.gridsuite.securityanalysis.server.service.SecurityAnalysisWorkerService.lambda$consumeRun$14(SecurityAnalysisWorkerService.java:296) at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.invokeConsumer(SimpleFunctionRegistry.java:987) --- .../SecurityAnalysisControllerTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java index fbc8cf87..9e91d8ff 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisControllerTest.java @@ -20,6 +20,7 @@ import com.powsybl.security.SecurityAnalysisResult; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus; import org.gridsuite.securityanalysis.server.service.ActionsService; +import org.gridsuite.securityanalysis.server.service.NotificationService; import org.gridsuite.securityanalysis.server.service.ReportService; import org.gridsuite.securityanalysis.server.service.SecurityAnalysisWorkerService; import org.gridsuite.securityanalysis.server.service.UuidGeneratorService; @@ -28,12 +29,15 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cloud.stream.binder.test.OutputDestination; import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; import org.springframework.http.MediaType; @@ -48,6 +52,8 @@ import java.lang.reflect.Constructor; import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import static com.powsybl.network.store.model.NetworkStoreApi.VERSION; import static org.gridsuite.securityanalysis.server.SecurityAnalysisProviderMock.*; @@ -56,6 +62,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; /** @@ -98,12 +105,17 @@ public class SecurityAnalysisControllerTest { @MockBean private UuidGeneratorService uuidGeneratorService; + @SpyBean + NotificationService notificationService; + @Autowired private SecurityAnalysisWorkerService workerService; @Autowired private ObjectMapper mapper; + ExecutorService executor = Executors.newSingleThreadExecutor(); + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -177,6 +189,22 @@ public void setUp() throws Exception { } while (output.receive(1000, "sa.failed") != null) { } + + // Emit messages in separate threads, like in production. + // Otherwise the test binder calls consumers directly in the caller thread. + // By coincidence, this leads to the following exception, + // because we use webflux for the controller (calller thread), + // and we use webflux to implement control flow in consumeRun + // > Exception in consumeRun java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread parallel-5 + doAnswer((InvocationOnMock invocation) -> + executor.submit(() -> { + try { + return invocation.callRealMethod(); + } catch (Throwable e) { + throw new RuntimeException("Error in test wrapping emit", e); + } + }) + ).when(notificationService).emitRunAnalysisMessage(Mockito.any()); } // added for testStatus can return null, after runTest