From f897ea34166a5f67859e2bd11284b16f16ed4106 Mon Sep 17 00:00:00 2001 From: Felix Reichenbach <felix.reichenbach@mgm-tp.com> Date: Mon, 17 Mar 2025 10:33:32 +0100 Subject: [PATCH] OZG-7573 imlemet RouteForwardingGrpcService with EingangStubReceiverStreamObserver --- .../eingang/forwarder/FileService.java | 19 ++ .../forwarder/RouteForwardingGrpcService.java | 37 +++- .../forwarder/RouteForwardingService.java | 5 + .../RouteForwardingGrpcServiceTest.java | 172 +++++++++++++++--- 4 files changed, 195 insertions(+), 38 deletions(-) create mode 100644 forwarder/src/main/java/de/ozgcloud/eingang/forwarder/FileService.java diff --git a/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/FileService.java b/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/FileService.java new file mode 100644 index 000000000..812748eb1 --- /dev/null +++ b/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/FileService.java @@ -0,0 +1,19 @@ +package de.ozgcloud.eingang.forwarder; + +import java.io.File; +import java.io.InputStream; +import java.util.concurrent.CompletableFuture; + +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +class FileService { + + @Async + public CompletableFuture<File> saveToFile(InputStream inputStream) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'saveToFile'"); + } + +} diff --git a/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcService.java b/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcService.java index 82f8ae332..322e7361f 100644 --- a/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcService.java +++ b/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcService.java @@ -23,9 +23,12 @@ */ package de.ozgcloud.eingang.forwarder; +import java.io.File; +import java.io.InputStream; +import java.util.concurrent.CompletableFuture; + import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingRequest; import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingResponse; -import de.ozgcloud.eingang.router.GrpcEingangMapper; import io.grpc.stub.StreamObserver; import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.server.service.GrpcService; @@ -34,17 +37,31 @@ import net.devh.boot.grpc.server.service.GrpcService; @RequiredArgsConstructor public class RouteForwardingGrpcService extends RouteForwardingServiceGrpc.RouteForwardingServiceImplBase { - private final RouteForwardingService service; - private final RouteCriteriaMapper criteriaMapper; - - private final GrpcEingangMapper eingangMapper; + private final RouteForwardingMapper routeForwardingMapper; + private final IncomingFileMapper incomingFileMapper; + private final IncomingFileGroupMapper incomingFileGroupMapper; + private final RouteForwardingService routeForwardingService; + private final FileService fileService; @Override public StreamObserver<GrpcRouteForwardingRequest> routeForwarding(StreamObserver<GrpcRouteForwardingResponse> responseObserver) { - // public void routeForwarding(GrpcRouteForwardingRequest request, - // StreamObserver<GrpcRouteForwardingResponse> responseObserver) { - // service.route(criteriaMapper.fromGrpc(request.getRouteCriteria()), - // eingangMapper.toFormData(request.getEingang())); - return null; + return EingangStubReceiverStreamObserver.builder() + .fileSaver(this::saveFile) + .routeForwardingMapper(routeForwardingMapper) + .incomingFileMapper(incomingFileMapper) + .incomingFileGroupMapper(incomingFileGroupMapper) + .formDataConsumer(routeForwardingService::route) + .responseConsumer(repsonse -> respondWith(responseObserver, repsonse)) + .build(); + } + + public CompletableFuture<File> saveFile(InputStream inputStream) { + return fileService.saveToFile(inputStream); } + + public void respondWith(StreamObserver<GrpcRouteForwardingResponse> responseObserver, GrpcRouteForwardingResponse response) { + responseObserver.onNext(response); + responseObserver.onCompleted(); + } + } diff --git a/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingService.java b/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingService.java index 8df1ca5ae..13058871d 100644 --- a/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingService.java +++ b/forwarder/src/main/java/de/ozgcloud/eingang/forwarder/RouteForwardingService.java @@ -45,4 +45,9 @@ class RouteForwardingService { .build()) .build()); } + + public void route(FormData formData) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'route'"); + } } diff --git a/forwarder/src/test/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcServiceTest.java b/forwarder/src/test/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcServiceTest.java index f4f0b4f64..35ac8140c 100644 --- a/forwarder/src/test/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcServiceTest.java +++ b/forwarder/src/test/java/de/ozgcloud/eingang/forwarder/RouteForwardingGrpcServiceTest.java @@ -23,70 +23,186 @@ */ package de.ozgcloud.eingang.forwarder; +import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import org.junit.jupiter.api.BeforeEach; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.InputStream; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; + import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.test.util.ReflectionTestUtils; + +import com.thedeanda.lorem.LoremIpsum; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingRequest; import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingResponse; -import de.ozgcloud.eingang.router.GrpcEingangMapper; import io.grpc.stub.StreamObserver; class RouteForwardingGrpcServiceTest { @InjectMocks + @Spy private RouteForwardingGrpcService service; @Mock private StreamObserver<GrpcRouteForwardingResponse> responseObserver; @Mock - private RouteForwardingService routeService; + private RouteForwardingMapper routeForwardingMapper; + @Mock + private IncomingFileMapper incomingFileMapper; @Mock - private RouteCriteriaMapper criteriaMapper; + private IncomingFileGroupMapper incomingFileGroupMapper; @Mock - private GrpcEingangMapper eingangMapper; + private RouteForwardingService routeForwardingService; + @Mock + private FileService fileService; @Nested class TestRouteForwarding { + private static final byte[] CONTENT = LoremIpsum.getInstance().getWords(5).getBytes(); + + private static final ByteArrayInputStream INPUT_STREAM = new ByteArrayInputStream(CONTENT); - private final RouteCriteria routeCriteria = RouteCriteriaTestFactory.create(); private final FormData formData = FormDataTestFactory.create(); - @BeforeEach - void mock() { - when(criteriaMapper.fromGrpc(any())).thenReturn(routeCriteria); - when(eingangMapper.toFormData(any())).thenReturn(formData); + @Test + void shouldSetFileSaver() { + var observer = service.routeForwarding(responseObserver); + + callFileSaver(observer); + verify(service).saveFile(INPUT_STREAM); + } + + @Test + void shouldSetRouteForwardingMapper() { + var observer = service.routeForwarding(responseObserver); + + assertThat(getRouteForwardingMapper(observer)).isEqualTo(routeForwardingMapper); + } + + @Test + void shouldSetIncomingFileMapper() { + var observer = service.routeForwarding(responseObserver); + + assertThat(getIncomingFileMapper(observer)).isEqualTo(incomingFileMapper); + } + + @Test + void shouldSetIncomingFileGroupMapper() { + var observer = service.routeForwarding(responseObserver); + + assertThat(getIncomingFileGroupMapper(observer)).isEqualTo(incomingFileGroupMapper); + } + + @Test + void shouldSetFormDataConsumer() { + var observer = service.routeForwarding(responseObserver); + + callFormDataConsumer(observer, formData); + verify(routeForwardingService).route(formData); + } + + @Test + void shouldSetResponseConsumer() { + var observer = service.routeForwarding(responseObserver); + + callResponseConsumer(observer, GrpcRouteForwardingResponse.getDefaultInstance()); + verify(service).respondWith(responseObserver, GrpcRouteForwardingResponse.getDefaultInstance()); + } + + @SuppressWarnings("unchecked") + private void callFileSaver(StreamObserver<GrpcRouteForwardingRequest> uploadObserver) { + var fileSaver = (Function<InputStream, CompletableFuture<File>>) ReflectionTestUtils.getField(uploadObserver, "fileSaver"); + fileSaver.apply(INPUT_STREAM); + } + + private RouteForwardingMapper getRouteForwardingMapper(StreamObserver<GrpcRouteForwardingRequest> uploadObserver) { + var routeForwardingMapper = (RouteForwardingMapper) ReflectionTestUtils.getField(uploadObserver, "routeForwardingMapper"); + return routeForwardingMapper; + } + + private IncomingFileMapper getIncomingFileMapper(StreamObserver<GrpcRouteForwardingRequest> uploadObserver) { + var incomingFileMapper = (IncomingFileMapper) ReflectionTestUtils.getField(uploadObserver, "incomingFileMapper"); + return incomingFileMapper; + } + + private IncomingFileGroupMapper getIncomingFileGroupMapper(StreamObserver<GrpcRouteForwardingRequest> uploadObserver) { + var incomingFileGroupMapper = (IncomingFileGroupMapper) ReflectionTestUtils.getField(uploadObserver, "incomingFileGroupMapper"); + return incomingFileGroupMapper; + } + + @SuppressWarnings("unchecked") + private void callFormDataConsumer(StreamObserver<GrpcRouteForwardingRequest> uploadObserver, FormData formData) { + var formDataConsumer = (Consumer<FormData>) ReflectionTestUtils.getField(uploadObserver, "formDataConsumer"); + formDataConsumer.accept(formData); + } + + @SuppressWarnings("unchecked") + private void callResponseConsumer(StreamObserver<GrpcRouteForwardingRequest> uploadObserver, GrpcRouteForwardingResponse response) { + var responseConsumer = (Consumer<GrpcRouteForwardingResponse>) ReflectionTestUtils.getField(uploadObserver, "responseConsumer"); + responseConsumer.accept(response); } + } + + @Nested + class TestSaveFile { - // @Test - // void shouldMapCriteria() { - // service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), - // responseObserver); + @Mock + private InputStream inputStream; + @Mock + private CompletableFuture<File> fileFuture; - // verify(criteriaMapper).fromGrpc(GrpcRouteForwardingRequestTestFactory.CRITERIA); - // } + @Test + void shouldReturnNull() { + service.saveFile(inputStream); - // @Test - // void shouldMapEingang() { - // service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), - // responseObserver); + verify(fileService).saveToFile(inputStream); + } - // verify(eingangMapper).toFormData(GrpcRouteForwardingRequestTestFactory.EINGANG); - // } + @Test + void shouldReturnFileFuture() { + when(fileService.saveToFile(any())).thenReturn(fileFuture); - // @Test - // void shouldCallService() { - // service.routeForwarding(GrpcRouteForwardingRequestTestFactory.create(), - // responseObserver); + var result = service.saveFile(inputStream); - // verify(routeService).route(routeCriteria, formData); - // } + assertThat(result).isSameAs(fileFuture); + } } + @Nested + class TestRespondWith { + + private GrpcRouteForwardingResponse response = GrpcRouteForwardingResponse.newBuilder().build(); + @Mock + private StreamObserver<GrpcRouteForwardingResponse> responseObserver; + + @Test + void shouldCallOnNext() { + service.respondWith(responseObserver, response); + + verify(responseObserver).onNext(response); + } + + @Test + void shouldCallOnCompletedAfterOnNext() { + var inOrder = inOrder(responseObserver); + + service.respondWith(responseObserver, response); + + inOrder.verify(responseObserver).onNext(response); + inOrder.verify(responseObserver).onCompleted(); + } + } } -- GitLab