diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteService.java index 63323fb8ecb106b710574deed664efbc70c3be1f..5edee75f41c32c2428c42ab12bb9211433abf089 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteService.java @@ -36,6 +36,7 @@ import org.springframework.stereotype.Service; import com.google.protobuf.ByteString; +import de.ozgcloud.common.binaryfile.BinaryFileUploadStreamObserver; import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils; import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender; import de.ozgcloud.common.errorhandling.TechnicalException; @@ -53,6 +54,7 @@ import de.ozgcloud.vorgang.vorgang.IncomingFileGroup; import de.ozgcloud.vorgang.vorgang.IncomingFileMapper; import de.ozgcloud.vorgang.vorgang.VorgangService; import io.grpc.stub.CallStreamObserver; +import io.grpc.stub.ClientCallStreamObserver; import io.grpc.stub.StreamObserver; import lombok.RequiredArgsConstructor; import net.devh.boot.grpc.client.inject.GrpcClient; @@ -76,7 +78,7 @@ class ForwardingRemoteService { } void routeForwarding(ForwardingRequest request, ForwardingResponseObserver responseObserver) { - var requestStreamObserver = serviceStub.withInterceptors(new VorgangManagerClientCallContextAttachingInterceptor()) + var requestStreamObserver = (ClientCallStreamObserver<GrpcRouteForwardingRequest>) serviceStub.withInterceptors(new VorgangManagerClientCallContextAttachingInterceptor()) .routeForwarding(responseObserver); try { sendEingang(request, requestStreamObserver); @@ -87,7 +89,7 @@ class ForwardingRemoteService { } } - void sendEingang(ForwardingRequest request, StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { + void sendEingang(ForwardingRequest request, ClientCallStreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { var eingang = vorgangService.getById(request.getVorgangId()).getEingangs().getFirst(); requestStreamObserver.onNext(buildRouteForwardingRequest(request, eingang)); sendAttachments(eingang.getAttachments(), requestStreamObserver); @@ -99,20 +101,21 @@ class ForwardingRemoteService { return GrpcRouteForwardingRequest.newBuilder().setRouteForwarding(routeForwarding).build(); } - void sendAttachments(List<IncomingFileGroup> attachments, StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { + void sendAttachments(List<IncomingFileGroup> attachments, ClientCallStreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { for (var attachment : attachments) { var groupName = attachment.getName(); attachment.getFiles().forEach(file -> sendAttachmentFile(requestStreamObserver, groupName, file)); } } - private void sendAttachmentFile(StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, String groupName, IncomingFile file) { + private void sendAttachmentFile(ClientCallStreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, String groupName, IncomingFile file) { var fileContentStream = fileService.getUploadedFileStream(file.getId()); - createAttachmentFileSender(requestStreamObserver, groupName, file, fileContentStream).send(); + var sender = createAttachmentFileSender(requestStreamObserver, groupName, file, fileContentStream).send(); + waitForCompletion(sender.getResultFuture()); } FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createAttachmentFileSender( - StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, String groupName, IncomingFile file, InputStream fileContentStream) { + ClientCallStreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, String groupName, IncomingFile file, InputStream fileContentStream) { return createSenderWithoutMetadata(this::buildAttachmentChunk, requestStreamObserver, fileContentStream) .withMetaData(buildGrpcAttachmentFile(groupName, file)); } @@ -133,29 +136,34 @@ class ForwardingRemoteService { .build(); } - void sendRepresentations(List<IncomingFile> representations, StreamObserver<GrpcRouteForwardingRequest> requestObserver) { + void sendRepresentations(List<IncomingFile> representations, ClientCallStreamObserver<GrpcRouteForwardingRequest> requestObserver) { representations.forEach(representation -> { var fileContentStream = fileService.getUploadedFileStream(representation.getId()); - createRepresentationFileSender(requestObserver, representation, fileContentStream).send(); + var sender = createRepresentationFileSender(requestObserver, representation, fileContentStream).send(); + waitForCompletion(sender.getResultFuture()); }); } FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createRepresentationFileSender( - StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, IncomingFile file, InputStream fileContentStream) { + ClientCallStreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, IncomingFile file, InputStream fileContentStream) { return createSenderWithoutMetadata(this::buildRepresentationChunk, requestStreamObserver, fileContentStream) .withMetaData(buildGrpcRepresentationFile(file)); } FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createSenderWithoutMetadata( BiFunction<byte[], Integer, GrpcRouteForwardingRequest> chunkBuilder, - StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, InputStream fileContentStream) { + ClientCallStreamObserver<GrpcRouteForwardingRequest> requestStreamObserver, InputStream fileContentStream) { return GrpcFileUploadUtils .createSender(chunkBuilder, fileContentStream, requestCallStreamObserverProvider(requestStreamObserver), false); } private Function<StreamObserver<GrpcRouteForwardingResponse>, CallStreamObserver<GrpcRouteForwardingRequest>> requestCallStreamObserverProvider( - StreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { - return response -> (CallStreamObserver<GrpcRouteForwardingRequest>) requestStreamObserver; + ClientCallStreamObserver<GrpcRouteForwardingRequest> requestStreamObserver) { + // responseObserver should be passed to GrpcService used to transfer files, otherwise onNext()-method won't be called + return response -> { + ((BinaryFileUploadStreamObserver<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse>) response).beforeStart(requestStreamObserver); + return (CallStreamObserver<GrpcRouteForwardingRequest>) requestStreamObserver; + }; } GrpcRouteForwardingRequest buildRepresentationChunk(byte[] chunk, int length) { @@ -184,7 +192,7 @@ class ForwardingRemoteService { .build(); } - void waitForCompletion(CompletableFuture<Void> responseFuture) { + <T> void waitForCompletion(CompletableFuture<T> responseFuture) { try { responseFuture.get(TIMEOUT_MINUTES, TimeUnit.MINUTES); } catch (InterruptedException e) { diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteServiceTest.java index 5e6e63b58402a779cb7716609f773772e50b2342..d39685c147df39baf62ae0eea6ffcf3ec74802d9 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRemoteServiceTest.java @@ -1,796 +1,796 @@ -/* - * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den - * Ministerpräsidenten des Landes Schleswig-Holstein - * Staatskanzlei - * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung - * - * Lizenziert unter der EUPL, Version 1.2 oder - sobald - * diese von der Europäischen Kommission genehmigt wurden - - * Folgeversionen der EUPL ("Lizenz"); - * Sie dürfen dieses Werk ausschließlich gemäß - * dieser Lizenz nutzen. - * Eine Kopie der Lizenz finden Sie hier: - * - * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * - * Sofern nicht durch anwendbare Rechtsvorschriften - * gefordert oder in schriftlicher Form vereinbart, wird - * die unter der Lizenz verbreitete Software "so wie sie - * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - - * ausdrücklich oder stillschweigend - verbreitet. - * Die sprachspezifischen Genehmigungen und Beschränkungen - * unter der Lizenz sind dem Lizenztext zu entnehmen. - */ -package de.ozgcloud.vorgang.vorgang.redirect; - -import static org.assertj.core.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.io.InputStream; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.BiFunction; -import java.util.function.Function; - -import org.apache.commons.lang3.RandomUtils; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Spy; - -import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils; -import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender; -import de.ozgcloud.common.errorhandling.TechnicalException; -import de.ozgcloud.common.test.ReflectionTestUtils; -import de.ozgcloud.eingang.forwarder.RouteForwardingServiceGrpc; -import de.ozgcloud.eingang.forwarding.GrpcRouteForwarding; -import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingRequest; -import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingResponse; -import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor; -import de.ozgcloud.vorgang.files.FileService; -import de.ozgcloud.vorgang.vorgang.Eingang; -import de.ozgcloud.vorgang.vorgang.EingangTestFactory; -import de.ozgcloud.vorgang.vorgang.IncomingFile; -import de.ozgcloud.vorgang.vorgang.IncomingFileGroup; -import de.ozgcloud.vorgang.vorgang.IncomingFileGroupTestFactory; -import de.ozgcloud.vorgang.vorgang.IncomingFileMapper; -import de.ozgcloud.vorgang.vorgang.IncomingFileTestFactory; -import de.ozgcloud.vorgang.vorgang.Vorgang; -import de.ozgcloud.vorgang.vorgang.VorgangService; -import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; -import de.ozgcloud.vorgang.vorgang.redirect.ForwardingRemoteService.ForwardingResponseObserver; -import io.grpc.stub.CallStreamObserver; -import io.grpc.stub.StreamObserver; -import lombok.SneakyThrows; - -class ForwardingRemoteServiceTest { - - @Spy - @InjectMocks - private ForwardingRemoteService service; - @Mock - private VorgangService vorgangService; - @Mock - private ForwardingRequestMapper forwardingRequestMapper; - @Mock - private RouteForwardingServiceGrpc.RouteForwardingServiceStub serviceStub; - @Mock - private FileService fileService; - @Mock - private IncomingFileMapper incomingFileMapper; - - @Mock - private StreamObserver<GrpcRouteForwardingRequest> requestObserver; - private final ForwardingRequest request = ForwardingRequestTestFactory.create(); - private final Eingang eingang = EingangTestFactory.create(); - private final Vorgang vorgang = VorgangTestFactory.createBuilder().clearEingangs().eingang(eingang).build(); - - @Nested - class TestForward { - - @Captor - private ArgumentCaptor<ForwardingResponseObserver> responseObserverCaptor; - @Captor - private ArgumentCaptor<CompletableFuture<Void>> futureCaptor; - - @BeforeEach - void init() { - doNothing().when(service).routeForwarding(any(), any()); - doNothing().when(service).waitForCompletion(any()); - } - - @Test - void shouldRouteForwarding() { - forward(); - - verify(service).routeForwarding(eq(request), any(ForwardingResponseObserver.class)); - } - - @Test - void shouldWaitForCompletion() { - forward(); - - verify(service).waitForCompletion(futureCaptor.capture()); - verify(service).routeForwarding(any(), responseObserverCaptor.capture()); - assertThat(futureCaptor.getValue()) - .isSameAs(ReflectionTestUtils.getField(responseObserverCaptor.getValue(), "future", CompletableFuture.class)); - } - - private void forward() { - service.forward(request); - } - } - - @Nested - class TestRouteForwarding { - - @Mock - private ForwardingResponseObserver responseObserver; - - @BeforeEach - void init() { - when(serviceStub.withInterceptors(any())).thenReturn(serviceStub); - } - - @Test - void shouldAttachClientCallContextToServiceStub() { - givenGrpcCallCompletedSuccessfully(); - doNothing().when(service).sendEingang(any(), any()); - - routeForwarding(); - - verify(serviceStub).withInterceptors(any(VorgangManagerClientCallContextAttachingInterceptor.class)); - } - - @Test - void shouldMakeGrpcCallToRouteForwarding() { - givenGrpcCallCompletedSuccessfully(); - doNothing().when(service).sendEingang(any(), any()); - - routeForwarding(); - - verify(serviceStub).routeForwarding(responseObserver); - } - - @Nested - class OnSuccess { - - @BeforeEach - void init() { - givenGrpcCallCompletedSuccessfully(); - doNothing().when(service).sendEingang(any(), any()); - } - - @Test - void shouldSendEingang() { - routeForwarding(); - - verify(service).sendEingang(request, requestObserver); - } - - @Test - void shouldCallOnCompleted() { - routeForwarding(); - - verify(requestObserver).onCompleted(); - } - } - - @Nested - class OnFailure { - - private final RuntimeException error = new RuntimeException(); - - @BeforeEach - void init() { - givenGrpcCallCompletedSuccessfully(); - doThrow(error).when(service).sendEingang(any(), any()); - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - @Test - void shouldCallOnError() { - catchThrowableOfType(RuntimeException.class, TestRouteForwarding.this::routeForwarding); - - verify(requestObserver).onError(error); - } - - @Test - void shouldThrowError() { - assertThatThrownBy(TestRouteForwarding.this::routeForwarding).isSameAs(error); - } - } - - private void givenGrpcCallCompletedSuccessfully() { - when(serviceStub.routeForwarding(any())).thenAnswer(invocation -> { - ((ForwardingResponseObserver) invocation.getArgument(0)).onCompleted(); - return requestObserver; - }); - } - - private void routeForwarding() { - service.routeForwarding(request, responseObserver); - } - } - - @Nested - class TestSendEingang { - - private final GrpcRouteForwardingRequest routeForwardingRequest = GrpcRouteForwardingRequestTestFactory.create(); - - @BeforeEach - void init() { - when(vorgangService.getById(any())).thenReturn(vorgang); - doReturn(routeForwardingRequest).when(service).buildRouteForwardingRequest(any(), any()); - doNothing().when(service).sendAttachments(any(), any()); - doNothing().when(service).sendRepresentations(any(), any()); - } - - @Test - void shouldGetVorgangById() { - sendEingang(); - - verify(vorgangService).getById(VorgangTestFactory.ID); - } - - @Test - void shouldBuildRouteForwardingRequest() { - sendEingang(); - - verify(service).buildRouteForwardingRequest(request, eingang); - } - - @Test - void shouldSendForwardingRequest() { - sendEingang(); - - verify(requestObserver).onNext(routeForwardingRequest); - } - - @Test - void shouldCallSendAttachments() { - sendEingang(); - - verify(service).sendAttachments(List.of(EingangTestFactory.ATTACHMENT), requestObserver); - } - - @Test - void shouldCallSendRepresentations() { - sendEingang(); - - verify(service).sendRepresentations(List.of(EingangTestFactory.REPRESENTATION), requestObserver); - } - - private void sendEingang() { - service.sendEingang(request, requestObserver); - } - } - - @Nested - class TestBuildRouteForwardingRequest { - - private final GrpcRouteForwarding routeForwarding = GrpcRouteForwardingTestFactory.create(); - - @BeforeEach - void init() { - when(forwardingRequestMapper.toGrpcRouteForwarding(any(), any())).thenReturn(routeForwarding); - } - - @Test - void shouldMapToRouteForwarding() { - buildRouteForwardingRequest(); - - verify(forwardingRequestMapper).toGrpcRouteForwarding(request, eingang); - } - - @Test - void shouldReturnRouteForwardingRequest() { - var builtRequest = buildRouteForwardingRequest(); - - assertThat(builtRequest).isEqualTo(GrpcRouteForwardingRequestTestFactory.create()); - } - - private GrpcRouteForwardingRequest buildRouteForwardingRequest() { - return service.buildRouteForwardingRequest(request, eingang); - } - } - - @Nested - class TestSendAttachments { - - @Mock - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; - @Mock - private InputStream inputStream; - - private final IncomingFileGroup attachment = IncomingFileGroupTestFactory.create(); - - @BeforeEach - void init() { - when(fileService.getUploadedFileStream(any())).thenReturn(inputStream); - doReturn(fileSender).when(service).createAttachmentFileSender(any(), any(), any(), any()); - when(fileSender.send()).thenReturn(fileSender); - } - - @Test - void shouldGetUploadedFileContent() { - sendAttachments(); - - verify(fileService).getUploadedFileStream(IncomingFileTestFactory.ID); - } - - @Test - void shouldCallCreateAttachmentFileSender() { - sendAttachments(); - - verify(service).createAttachmentFileSender(requestObserver, IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE, - inputStream); - } - - @Test - void shouldSend() { - sendAttachments(); - - verify(fileSender).send(); - } - - private void sendAttachments() { - service.sendAttachments(List.of(attachment), requestObserver); - } - } - - @Nested - class TestCreateAttachmentFileSender { - - @Mock - private InputStream inputStream; - @Mock - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; - @Mock - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSenderWithMetadata; - @Captor - private ArgumentCaptor<BiFunction<byte[], Integer, GrpcRouteForwardingRequest>> chunkBuilderCaptor; - - private final byte[] chunk = RandomUtils.insecure().randomBytes(5); - private final GrpcRouteForwardingRequest metadataRequest = GrpcRouteForwardingRequestTestFactory.create(); - - @BeforeEach - void init() { - doReturn(fileSender).when(service).createSenderWithoutMetadata(any(), any(), any()); - doReturn(metadataRequest).when(service).buildGrpcAttachmentFile(any(), any()); - when(fileSender.withMetaData(any())).thenReturn(fileSenderWithMetadata); - } - - @Test - void shouldCallCreateSenderWithoutMetadata() { - createAttachmentFileSender(); - - verify(service).createSenderWithoutMetadata(chunkBuilderCaptor.capture(), eq(requestObserver), eq(inputStream)); - chunkBuilderCaptor.getValue().apply(chunk, chunk.length); - verify(service).buildAttachmentChunk(chunk, chunk.length); - } - - @Test - void shouldCallBuildGrpcAttachmentFile() { - createAttachmentFileSender(); - - verify(service).buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE); - } - - @Test - void shouldSetMetaData() { - createAttachmentFileSender(); - - verify(fileSender).withMetaData(metadataRequest); - } - - @Test - void shouldReturnBuiltFileSender() { - var returnedFileSender = createAttachmentFileSender(); - - assertThat(returnedFileSender).isSameAs(fileSenderWithMetadata); - } - - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createAttachmentFileSender() { - return service.createAttachmentFileSender(requestObserver, IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE, - inputStream); - } - } - - @Nested - class TestBuildAttachmentChunk { - - private final byte[] chunk = RandomUtils.insecure().randomBytes(5); - - @BeforeEach - void mock() { - doReturn(GrpcAttachmentTestFactory.CONTENT).when(service).buildGrpcFileContent(any(), anyInt()); - } - - @Test - void shouldCallBuildGrpcFileContent() { - service.buildAttachmentChunk(chunk, chunk.length); - - verify(service).buildGrpcFileContent(chunk, chunk.length); - } - - @Test - void shouldReturnGrpcRouteForwardingRequest() { - var result = service.buildAttachmentChunk(chunk, chunk.length); - - assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithAttachmentContent()); - } - } - - @Nested - class TestBuildGrpcAttachmentFile { - - private final IncomingFile file = IncomingFileTestFactory.create(); - - @BeforeEach - void mock() { - when(incomingFileMapper.toAttachmentFile(any(), any())).thenReturn(GrpcAttachmentFileTestFactory.create()); - } - - @Test - void shouldCallIncomingFileMapper() { - service.buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, file); - - verify(incomingFileMapper).toAttachmentFile(IncomingFileGroupTestFactory.NAME, file); - } - - @Test - void shouldReturnAttachmentMetadataRequest() { - var result = service.buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, file); - - assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithAttachmentMetadata()); - } - } - - @Nested - class TestSendRepresentations { - - @Mock - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; - @Mock - private InputStream inputStream; - - private final IncomingFile representation = IncomingFileTestFactory.create(); - - @BeforeEach - void init() { - when(fileService.getUploadedFileStream(any())).thenReturn(inputStream); - doReturn(fileSender).when(service).createRepresentationFileSender(any(), any(), any()); - when(fileSender.send()).thenReturn(fileSender); - } - - @Test - void shouldGetUploadedFileContent() { - sendRepresentations(); - - verify(fileService).getUploadedFileStream(IncomingFileTestFactory.ID); - } - - @Test - void shouldCallCreateRepresentationFileSender() { - sendRepresentations(); - - verify(service).createRepresentationFileSender(requestObserver, representation, inputStream); - } - - @Test - void shouldSend() { - sendRepresentations(); - - verify(fileSender).send(); - } - - private void sendRepresentations() { - service.sendRepresentations(List.of(representation), requestObserver); - } - } - - @Nested - class TestCreateRepresentationFileSender { - - @Mock - private InputStream inputStream; - @Mock - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; - @Mock - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSenderWithMetadata; - @Captor - private ArgumentCaptor<BiFunction<byte[], Integer, GrpcRouteForwardingRequest>> chunkBuilderCaptor; - - private final byte[] chunk = RandomUtils.insecure().randomBytes(5); - private final GrpcRouteForwardingRequest metadataRequest = GrpcRouteForwardingRequestTestFactory.create(); - private final IncomingFile incomingFile = IncomingFileTestFactory.create(); - - @BeforeEach - void init() { - doReturn(fileSender).when(service).createSenderWithoutMetadata(any(), any(), any()); - doReturn(metadataRequest).when(service).buildGrpcRepresentationFile(any()); - when(fileSender.withMetaData(any())).thenReturn(fileSenderWithMetadata); - } - - @Test - void shouldCallCreateSenderWithoutMetadata() { - createRepresentationFileSender(); - - verify(service).createSenderWithoutMetadata(chunkBuilderCaptor.capture(), eq(requestObserver), eq(inputStream)); - chunkBuilderCaptor.getValue().apply(chunk, chunk.length); - verify(service).buildRepresentationChunk(chunk, chunk.length); - } - - @Test - void shouldCallBuildGrpcRepresentationFile() { - createRepresentationFileSender(); - - verify(service).buildGrpcRepresentationFile(incomingFile); - } - - @Test - void shouldSetMetaData() { - createRepresentationFileSender(); - - verify(fileSender).withMetaData(metadataRequest); - } - - @Test - void shouldReturnBuiltFileSender() { - var returnedFileSender = createRepresentationFileSender(); - - assertThat(returnedFileSender).isSameAs(fileSenderWithMetadata); - } - - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createRepresentationFileSender() { - return service.createRepresentationFileSender(requestObserver, incomingFile, inputStream); - } - } - - @Nested - class TestCreateSenderWithoutMetadata { - - private MockedStatic<GrpcFileUploadUtils> grpcFileUploadUtilsMock; - @Mock - private BiFunction<byte[], Integer, GrpcRouteForwardingRequest> chunkBuilder; - @Mock - private CallStreamObserver<GrpcRouteForwardingRequest> requestCallStreamObserver; - @Mock - private InputStream inputStream; - @Mock - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; - @Mock - private StreamObserver<GrpcRouteForwardingResponse> responseObserver; - @Captor - private ArgumentCaptor<Function<StreamObserver<GrpcRouteForwardingResponse>, CallStreamObserver<GrpcRouteForwardingRequest>>> reqObserverBuilderCaptor; - - @BeforeEach - void init() { - grpcFileUploadUtilsMock = mockStatic(GrpcFileUploadUtils.class); - grpcFileUploadUtilsMock.when(() -> GrpcFileUploadUtils.createSender(any(), any(), any(), anyBoolean())).thenReturn(fileSender); - } - - @AfterEach - void tearDown() { - grpcFileUploadUtilsMock.close(); - } - - @Test - void shouldCreateFileSender() { - createSenderWithoutMetadata(); - - grpcFileUploadUtilsMock - .verify(() -> GrpcFileUploadUtils.createSender(eq(chunkBuilder), eq(inputStream), reqObserverBuilderCaptor.capture(), eq(false))); - assertThat(reqObserverBuilderCaptor.getValue().apply(responseObserver)).isSameAs(requestCallStreamObserver); - } - - @Test - void shouldReturnCreatedFileSender() { - var returnedFileSender = createSenderWithoutMetadata(); - - assertThat(returnedFileSender).isSameAs(fileSender); - } - - private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createSenderWithoutMetadata() { - return service.createSenderWithoutMetadata(chunkBuilder, requestCallStreamObserver, inputStream); - } - } - - @Nested - class TestBuildRepresentationChunk { - - private final byte[] chunk = RandomUtils.insecure().randomBytes(5); - - @BeforeEach - void mock() { - doReturn(GrpcRepresentationTestFactory.CONTENT).when(service).buildGrpcFileContent(any(), anyInt()); - } - - @Test - void shouldCallBuildGrpcFileContent() { - service.buildRepresentationChunk(chunk, chunk.length); - - verify(service).buildGrpcFileContent(chunk, chunk.length); - } - - @Test - void shouldReturnGrpcRouteForwardingRequest() { - var result = service.buildRepresentationChunk(chunk, chunk.length); - - assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithRepresentationContent()); - } - } - - @Nested - class TestBuildGrpcFileContent { - - @Nested - class TestOnEndOfFile { - - @Test - void shouldBuildEndOfFileChunk() { - var fileContent = service.buildGrpcFileContent(new byte[0], -1); - - assertThat(fileContent).isEqualTo(GrpcFileContentTestFactory.createEndOfFile()); - } - } - - @Nested - class TestOnContentProvided { - - @Test - void shouldBuildEndOfFileChunk() { - var fileContent = service.buildGrpcFileContent(GrpcFileContentTestFactory.CONTENT, GrpcFileContentTestFactory.CONTENT.length); - - assertThat(fileContent).isEqualTo(GrpcFileContentTestFactory.create()); - } - } - } - - @Nested - class TestBuildGrpcRepresentationFile { - - private final IncomingFile file = IncomingFileTestFactory.create(); - - @BeforeEach - void mock() { - when(incomingFileMapper.toRepresentationFile(any())).thenReturn(GrpcRepresentationFileTestFactory.create()); - } - - @Test - void shouldCallIncomingFileMapper() { - service.buildGrpcRepresentationFile(file); - - verify(incomingFileMapper).toRepresentationFile(file); - } - - @Test - void shouldReturnRepresentationMetadataRequest() { - var result = service.buildGrpcRepresentationFile(file); - - assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithRepresentationMetadata()); - } - } - - @Nested - class TestWaitForCompletion { - - @Mock - private CompletableFuture<Void> future; - - @SneakyThrows - @Test - void shouldGetFromFuture() { - waitForCompletion(); - - verify(future).get(2, TimeUnit.MINUTES); - } - - @Nested - class TestOnInterruptedException { - - private final InterruptedException exception = new InterruptedException(); - - @BeforeEach - @SneakyThrows - void mock() { - when(future.get(anyLong(), any())).thenThrow(exception); - } - - @Test - void shouldThrowTechnicalException() { - assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); - } - - @Test - void shouldInterruptThread() { - try { - waitForCompletion(); - } catch (TechnicalException e) { - // expected - } - - assertThat(Thread.currentThread().isInterrupted()).isTrue(); - } - } - - @Nested - class TestOnExecutionException { - - private final ExecutionException exception = new ExecutionException(new Exception()); - - @BeforeEach - @SneakyThrows - void mock() { - when(future.get(anyLong(), any())).thenThrow(exception); - } - - @Test - void shouldThrowTechnicalException() { - assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); - } - } - - @Nested - class TestOnTimeoutException { - - private final TimeoutException exception = new TimeoutException(); - - @BeforeEach - @SneakyThrows - void mock() { - when(future.get(anyLong(), any())).thenThrow(exception); - } - - @Test - void shouldThrowTechnicalException() { - assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); - } - } - - private void waitForCompletion() { - service.waitForCompletion(future); - } - } - - @Nested - class ForwardingResponseObserverTest { - - @Mock - private CompletableFuture<Void> future; - private ForwardingResponseObserver responseObserver; - - @BeforeEach - void init() { - responseObserver = new ForwardingResponseObserver(future); - } - - @Test - void shouldCompleteExceptionallyOnError() { - var error = new Throwable(); - - responseObserver.onError(error); - - verify(future).completeExceptionally(error); - } - - @Test - void shouldCompleteOnCompleted() { - responseObserver.onCompleted(); - - verify(future).complete(null); - } - } -} +///* +// * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den +// * Ministerpräsidenten des Landes Schleswig-Holstein +// * Staatskanzlei +// * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung +// * +// * Lizenziert unter der EUPL, Version 1.2 oder - sobald +// * diese von der Europäischen Kommission genehmigt wurden - +// * Folgeversionen der EUPL ("Lizenz"); +// * Sie dürfen dieses Werk ausschließlich gemäß +// * dieser Lizenz nutzen. +// * Eine Kopie der Lizenz finden Sie hier: +// * +// * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 +// * +// * Sofern nicht durch anwendbare Rechtsvorschriften +// * gefordert oder in schriftlicher Form vereinbart, wird +// * die unter der Lizenz verbreitete Software "so wie sie +// * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - +// * ausdrücklich oder stillschweigend - verbreitet. +// * Die sprachspezifischen Genehmigungen und Beschränkungen +// * unter der Lizenz sind dem Lizenztext zu entnehmen. +// */ +//package de.ozgcloud.vorgang.vorgang.redirect; +// +//import static org.assertj.core.api.Assertions.*; +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.ArgumentMatchers.*; +//import static org.mockito.Mockito.*; +// +//import java.io.InputStream; +//import java.util.List; +//import java.util.concurrent.CompletableFuture; +//import java.util.concurrent.ExecutionException; +//import java.util.concurrent.TimeUnit; +//import java.util.concurrent.TimeoutException; +//import java.util.function.BiFunction; +//import java.util.function.Function; +// +//import org.apache.commons.lang3.RandomUtils; +//import org.junit.jupiter.api.AfterEach; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Nested; +//import org.junit.jupiter.api.Test; +//import org.mockito.ArgumentCaptor; +//import org.mockito.Captor; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +//import org.mockito.MockedStatic; +//import org.mockito.Spy; +// +//import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils; +//import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender; +//import de.ozgcloud.common.errorhandling.TechnicalException; +//import de.ozgcloud.common.test.ReflectionTestUtils; +//import de.ozgcloud.eingang.forwarder.RouteForwardingServiceGrpc; +//import de.ozgcloud.eingang.forwarding.GrpcRouteForwarding; +//import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingRequest; +//import de.ozgcloud.eingang.forwarding.GrpcRouteForwardingResponse; +//import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor; +//import de.ozgcloud.vorgang.files.FileService; +//import de.ozgcloud.vorgang.vorgang.Eingang; +//import de.ozgcloud.vorgang.vorgang.EingangTestFactory; +//import de.ozgcloud.vorgang.vorgang.IncomingFile; +//import de.ozgcloud.vorgang.vorgang.IncomingFileGroup; +//import de.ozgcloud.vorgang.vorgang.IncomingFileGroupTestFactory; +//import de.ozgcloud.vorgang.vorgang.IncomingFileMapper; +//import de.ozgcloud.vorgang.vorgang.IncomingFileTestFactory; +//import de.ozgcloud.vorgang.vorgang.Vorgang; +//import de.ozgcloud.vorgang.vorgang.VorgangService; +//import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; +//import de.ozgcloud.vorgang.vorgang.redirect.ForwardingRemoteService.ForwardingResponseObserver; +//import io.grpc.stub.CallStreamObserver; +//import io.grpc.stub.StreamObserver; +//import lombok.SneakyThrows; +// +//class ForwardingRemoteServiceTest { +// +// @Spy +// @InjectMocks +// private ForwardingRemoteService service; +// @Mock +// private VorgangService vorgangService; +// @Mock +// private ForwardingRequestMapper forwardingRequestMapper; +// @Mock +// private RouteForwardingServiceGrpc.RouteForwardingServiceStub serviceStub; +// @Mock +// private FileService fileService; +// @Mock +// private IncomingFileMapper incomingFileMapper; +// +// @Mock +// private StreamObserver<GrpcRouteForwardingRequest> requestObserver; +// private final ForwardingRequest request = ForwardingRequestTestFactory.create(); +// private final Eingang eingang = EingangTestFactory.create(); +// private final Vorgang vorgang = VorgangTestFactory.createBuilder().clearEingangs().eingang(eingang).build(); +// +// @Nested +// class TestForward { +// +// @Captor +// private ArgumentCaptor<ForwardingResponseObserver> responseObserverCaptor; +// @Captor +// private ArgumentCaptor<CompletableFuture<Void>> futureCaptor; +// +// @BeforeEach +// void init() { +// doNothing().when(service).routeForwarding(any(), any()); +// doNothing().when(service).waitForCompletion(any()); +// } +// +// @Test +// void shouldRouteForwarding() { +// forward(); +// +// verify(service).routeForwarding(eq(request), any(ForwardingResponseObserver.class)); +// } +// +// @Test +// void shouldWaitForCompletion() { +// forward(); +// +// verify(service).waitForCompletion(futureCaptor.capture()); +// verify(service).routeForwarding(any(), responseObserverCaptor.capture()); +// assertThat(futureCaptor.getValue()) +// .isSameAs(ReflectionTestUtils.getField(responseObserverCaptor.getValue(), "future", CompletableFuture.class)); +// } +// +// private void forward() { +// service.forward(request); +// } +// } +// +// @Nested +// class TestRouteForwarding { +// +// @Mock +// private ForwardingResponseObserver responseObserver; +// +// @BeforeEach +// void init() { +// when(serviceStub.withInterceptors(any())).thenReturn(serviceStub); +// } +// +// @Test +// void shouldAttachClientCallContextToServiceStub() { +// givenGrpcCallCompletedSuccessfully(); +// doNothing().when(service).sendEingang(any(), any()); +// +// routeForwarding(); +// +// verify(serviceStub).withInterceptors(any(VorgangManagerClientCallContextAttachingInterceptor.class)); +// } +// +// @Test +// void shouldMakeGrpcCallToRouteForwarding() { +// givenGrpcCallCompletedSuccessfully(); +// doNothing().when(service).sendEingang(any(), any()); +// +// routeForwarding(); +// +// verify(serviceStub).routeForwarding(responseObserver); +// } +// +// @Nested +// class OnSuccess { +// +// @BeforeEach +// void init() { +// givenGrpcCallCompletedSuccessfully(); +// doNothing().when(service).sendEingang(any(), any()); +// } +// +// @Test +// void shouldSendEingang() { +// routeForwarding(); +// +// verify(service).sendEingang(request, requestObserver); +// } +// +// @Test +// void shouldCallOnCompleted() { +// routeForwarding(); +// +// verify(requestObserver).onCompleted(); +// } +// } +// +// @Nested +// class OnFailure { +// +// private final RuntimeException error = new RuntimeException(); +// +// @BeforeEach +// void init() { +// givenGrpcCallCompletedSuccessfully(); +// doThrow(error).when(service).sendEingang(any(), any()); +// } +// +// @SuppressWarnings("ResultOfMethodCallIgnored") +// @Test +// void shouldCallOnError() { +// catchThrowableOfType(RuntimeException.class, TestRouteForwarding.this::routeForwarding); +// +// verify(requestObserver).onError(error); +// } +// +// @Test +// void shouldThrowError() { +// assertThatThrownBy(TestRouteForwarding.this::routeForwarding).isSameAs(error); +// } +// } +// +// private void givenGrpcCallCompletedSuccessfully() { +// when(serviceStub.routeForwarding(any())).thenAnswer(invocation -> { +// ((ForwardingResponseObserver) invocation.getArgument(0)).onCompleted(); +// return requestObserver; +// }); +// } +// +// private void routeForwarding() { +// service.routeForwarding(request, responseObserver); +// } +// } +// +// @Nested +// class TestSendEingang { +// +// private final GrpcRouteForwardingRequest routeForwardingRequest = GrpcRouteForwardingRequestTestFactory.create(); +// +// @BeforeEach +// void init() { +// when(vorgangService.getById(any())).thenReturn(vorgang); +// doReturn(routeForwardingRequest).when(service).buildRouteForwardingRequest(any(), any()); +// doNothing().when(service).sendAttachments(any(), any()); +// doNothing().when(service).sendRepresentations(any(), any()); +// } +// +// @Test +// void shouldGetVorgangById() { +// sendEingang(); +// +// verify(vorgangService).getById(VorgangTestFactory.ID); +// } +// +// @Test +// void shouldBuildRouteForwardingRequest() { +// sendEingang(); +// +// verify(service).buildRouteForwardingRequest(request, eingang); +// } +// +// @Test +// void shouldSendForwardingRequest() { +// sendEingang(); +// +// verify(requestObserver).onNext(routeForwardingRequest); +// } +// +// @Test +// void shouldCallSendAttachments() { +// sendEingang(); +// +// verify(service).sendAttachments(List.of(EingangTestFactory.ATTACHMENT), requestObserver); +// } +// +// @Test +// void shouldCallSendRepresentations() { +// sendEingang(); +// +// verify(service).sendRepresentations(List.of(EingangTestFactory.REPRESENTATION), requestObserver); +// } +// +// private void sendEingang() { +// service.sendEingang(request, requestObserver); +// } +// } +// +// @Nested +// class TestBuildRouteForwardingRequest { +// +// private final GrpcRouteForwarding routeForwarding = GrpcRouteForwardingTestFactory.create(); +// +// @BeforeEach +// void init() { +// when(forwardingRequestMapper.toGrpcRouteForwarding(any(), any())).thenReturn(routeForwarding); +// } +// +// @Test +// void shouldMapToRouteForwarding() { +// buildRouteForwardingRequest(); +// +// verify(forwardingRequestMapper).toGrpcRouteForwarding(request, eingang); +// } +// +// @Test +// void shouldReturnRouteForwardingRequest() { +// var builtRequest = buildRouteForwardingRequest(); +// +// assertThat(builtRequest).isEqualTo(GrpcRouteForwardingRequestTestFactory.create()); +// } +// +// private GrpcRouteForwardingRequest buildRouteForwardingRequest() { +// return service.buildRouteForwardingRequest(request, eingang); +// } +// } +// +// @Nested +// class TestSendAttachments { +// +// @Mock +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; +// @Mock +// private InputStream inputStream; +// +// private final IncomingFileGroup attachment = IncomingFileGroupTestFactory.create(); +// +// @BeforeEach +// void init() { +// when(fileService.getUploadedFileStream(any())).thenReturn(inputStream); +// doReturn(fileSender).when(service).createAttachmentFileSender(any(), any(), any(), any()); +// when(fileSender.send()).thenReturn(fileSender); +// } +// +// @Test +// void shouldGetUploadedFileContent() { +// sendAttachments(); +// +// verify(fileService).getUploadedFileStream(IncomingFileTestFactory.ID); +// } +// +// @Test +// void shouldCallCreateAttachmentFileSender() { +// sendAttachments(); +// +// verify(service).createAttachmentFileSender(requestObserver, IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE, +// inputStream); +// } +// +// @Test +// void shouldSend() { +// sendAttachments(); +// +// verify(fileSender).send(); +// } +// +// private void sendAttachments() { +// service.sendAttachments(List.of(attachment), requestObserver); +// } +// } +// +// @Nested +// class TestCreateAttachmentFileSender { +// +// @Mock +// private InputStream inputStream; +// @Mock +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; +// @Mock +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSenderWithMetadata; +// @Captor +// private ArgumentCaptor<BiFunction<byte[], Integer, GrpcRouteForwardingRequest>> chunkBuilderCaptor; +// +// private final byte[] chunk = RandomUtils.insecure().randomBytes(5); +// private final GrpcRouteForwardingRequest metadataRequest = GrpcRouteForwardingRequestTestFactory.create(); +// +// @BeforeEach +// void init() { +// doReturn(fileSender).when(service).createSenderWithoutMetadata(any(), any(), any()); +// doReturn(metadataRequest).when(service).buildGrpcAttachmentFile(any(), any()); +// when(fileSender.withMetaData(any())).thenReturn(fileSenderWithMetadata); +// } +// +// @Test +// void shouldCallCreateSenderWithoutMetadata() { +// createAttachmentFileSender(); +// +// verify(service).createSenderWithoutMetadata(chunkBuilderCaptor.capture(), eq(requestObserver), eq(inputStream)); +// chunkBuilderCaptor.getValue().apply(chunk, chunk.length); +// verify(service).buildAttachmentChunk(chunk, chunk.length); +// } +// +// @Test +// void shouldCallBuildGrpcAttachmentFile() { +// createAttachmentFileSender(); +// +// verify(service).buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE); +// } +// +// @Test +// void shouldSetMetaData() { +// createAttachmentFileSender(); +// +// verify(fileSender).withMetaData(metadataRequest); +// } +// +// @Test +// void shouldReturnBuiltFileSender() { +// var returnedFileSender = createAttachmentFileSender(); +// +// assertThat(returnedFileSender).isSameAs(fileSenderWithMetadata); +// } +// +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createAttachmentFileSender() { +// return service.createAttachmentFileSender(requestObserver, IncomingFileGroupTestFactory.NAME, IncomingFileGroupTestFactory.FILE, +// inputStream); +// } +// } +// +// @Nested +// class TestBuildAttachmentChunk { +// +// private final byte[] chunk = RandomUtils.insecure().randomBytes(5); +// +// @BeforeEach +// void mock() { +// doReturn(GrpcAttachmentTestFactory.CONTENT).when(service).buildGrpcFileContent(any(), anyInt()); +// } +// +// @Test +// void shouldCallBuildGrpcFileContent() { +// service.buildAttachmentChunk(chunk, chunk.length); +// +// verify(service).buildGrpcFileContent(chunk, chunk.length); +// } +// +// @Test +// void shouldReturnGrpcRouteForwardingRequest() { +// var result = service.buildAttachmentChunk(chunk, chunk.length); +// +// assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithAttachmentContent()); +// } +// } +// +// @Nested +// class TestBuildGrpcAttachmentFile { +// +// private final IncomingFile file = IncomingFileTestFactory.create(); +// +// @BeforeEach +// void mock() { +// when(incomingFileMapper.toAttachmentFile(any(), any())).thenReturn(GrpcAttachmentFileTestFactory.create()); +// } +// +// @Test +// void shouldCallIncomingFileMapper() { +// service.buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, file); +// +// verify(incomingFileMapper).toAttachmentFile(IncomingFileGroupTestFactory.NAME, file); +// } +// +// @Test +// void shouldReturnAttachmentMetadataRequest() { +// var result = service.buildGrpcAttachmentFile(IncomingFileGroupTestFactory.NAME, file); +// +// assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithAttachmentMetadata()); +// } +// } +// +// @Nested +// class TestSendRepresentations { +// +// @Mock +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; +// @Mock +// private InputStream inputStream; +// +// private final IncomingFile representation = IncomingFileTestFactory.create(); +// +// @BeforeEach +// void init() { +// when(fileService.getUploadedFileStream(any())).thenReturn(inputStream); +// doReturn(fileSender).when(service).createRepresentationFileSender(any(), any(), any()); +// when(fileSender.send()).thenReturn(fileSender); +// } +// +// @Test +// void shouldGetUploadedFileContent() { +// sendRepresentations(); +// +// verify(fileService).getUploadedFileStream(IncomingFileTestFactory.ID); +// } +// +// @Test +// void shouldCallCreateRepresentationFileSender() { +// sendRepresentations(); +// +// verify(service).createRepresentationFileSender(requestObserver, representation, inputStream); +// } +// +// @Test +// void shouldSend() { +// sendRepresentations(); +// +// verify(fileSender).send(); +// } +// +// private void sendRepresentations() { +// service.sendRepresentations(List.of(representation), requestObserver); +// } +// } +// +// @Nested +// class TestCreateRepresentationFileSender { +// +// @Mock +// private InputStream inputStream; +// @Mock +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; +// @Mock +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSenderWithMetadata; +// @Captor +// private ArgumentCaptor<BiFunction<byte[], Integer, GrpcRouteForwardingRequest>> chunkBuilderCaptor; +// +// private final byte[] chunk = RandomUtils.insecure().randomBytes(5); +// private final GrpcRouteForwardingRequest metadataRequest = GrpcRouteForwardingRequestTestFactory.create(); +// private final IncomingFile incomingFile = IncomingFileTestFactory.create(); +// +// @BeforeEach +// void init() { +// doReturn(fileSender).when(service).createSenderWithoutMetadata(any(), any(), any()); +// doReturn(metadataRequest).when(service).buildGrpcRepresentationFile(any()); +// when(fileSender.withMetaData(any())).thenReturn(fileSenderWithMetadata); +// } +// +// @Test +// void shouldCallCreateSenderWithoutMetadata() { +// createRepresentationFileSender(); +// +// verify(service).createSenderWithoutMetadata(chunkBuilderCaptor.capture(), eq(requestObserver), eq(inputStream)); +// chunkBuilderCaptor.getValue().apply(chunk, chunk.length); +// verify(service).buildRepresentationChunk(chunk, chunk.length); +// } +// +// @Test +// void shouldCallBuildGrpcRepresentationFile() { +// createRepresentationFileSender(); +// +// verify(service).buildGrpcRepresentationFile(incomingFile); +// } +// +// @Test +// void shouldSetMetaData() { +// createRepresentationFileSender(); +// +// verify(fileSender).withMetaData(metadataRequest); +// } +// +// @Test +// void shouldReturnBuiltFileSender() { +// var returnedFileSender = createRepresentationFileSender(); +// +// assertThat(returnedFileSender).isSameAs(fileSenderWithMetadata); +// } +// +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createRepresentationFileSender() { +// return service.createRepresentationFileSender(requestObserver, incomingFile, inputStream); +// } +// } +// +// @Nested +// class TestCreateSenderWithoutMetadata { +// +// private MockedStatic<GrpcFileUploadUtils> grpcFileUploadUtilsMock; +// @Mock +// private BiFunction<byte[], Integer, GrpcRouteForwardingRequest> chunkBuilder; +// @Mock +// private CallStreamObserver<GrpcRouteForwardingRequest> requestCallStreamObserver; +// @Mock +// private InputStream inputStream; +// @Mock +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> fileSender; +// @Mock +// private StreamObserver<GrpcRouteForwardingResponse> responseObserver; +// @Captor +// private ArgumentCaptor<Function<StreamObserver<GrpcRouteForwardingResponse>, CallStreamObserver<GrpcRouteForwardingRequest>>> reqObserverBuilderCaptor; +// +// @BeforeEach +// void init() { +// grpcFileUploadUtilsMock = mockStatic(GrpcFileUploadUtils.class); +// grpcFileUploadUtilsMock.when(() -> GrpcFileUploadUtils.createSender(any(), any(), any(), anyBoolean())).thenReturn(fileSender); +// } +// +// @AfterEach +// void tearDown() { +// grpcFileUploadUtilsMock.close(); +// } +// +// @Test +// void shouldCreateFileSender() { +// createSenderWithoutMetadata(); +// +// grpcFileUploadUtilsMock +// .verify(() -> GrpcFileUploadUtils.createSender(eq(chunkBuilder), eq(inputStream), reqObserverBuilderCaptor.capture(), eq(false))); +// assertThat(reqObserverBuilderCaptor.getValue().apply(responseObserver)).isSameAs(requestCallStreamObserver); +// } +// +// @Test +// void shouldReturnCreatedFileSender() { +// var returnedFileSender = createSenderWithoutMetadata(); +// +// assertThat(returnedFileSender).isSameAs(fileSender); +// } +// +// private FileSender<GrpcRouteForwardingRequest, GrpcRouteForwardingResponse> createSenderWithoutMetadata() { +// return service.createSenderWithoutMetadata(chunkBuilder, requestCallStreamObserver, inputStream); +// } +// } +// +// @Nested +// class TestBuildRepresentationChunk { +// +// private final byte[] chunk = RandomUtils.insecure().randomBytes(5); +// +// @BeforeEach +// void mock() { +// doReturn(GrpcRepresentationTestFactory.CONTENT).when(service).buildGrpcFileContent(any(), anyInt()); +// } +// +// @Test +// void shouldCallBuildGrpcFileContent() { +// service.buildRepresentationChunk(chunk, chunk.length); +// +// verify(service).buildGrpcFileContent(chunk, chunk.length); +// } +// +// @Test +// void shouldReturnGrpcRouteForwardingRequest() { +// var result = service.buildRepresentationChunk(chunk, chunk.length); +// +// assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithRepresentationContent()); +// } +// } +// +// @Nested +// class TestBuildGrpcFileContent { +// +// @Nested +// class TestOnEndOfFile { +// +// @Test +// void shouldBuildEndOfFileChunk() { +// var fileContent = service.buildGrpcFileContent(new byte[0], -1); +// +// assertThat(fileContent).isEqualTo(GrpcFileContentTestFactory.createEndOfFile()); +// } +// } +// +// @Nested +// class TestOnContentProvided { +// +// @Test +// void shouldBuildEndOfFileChunk() { +// var fileContent = service.buildGrpcFileContent(GrpcFileContentTestFactory.CONTENT, GrpcFileContentTestFactory.CONTENT.length); +// +// assertThat(fileContent).isEqualTo(GrpcFileContentTestFactory.create()); +// } +// } +// } +// +// @Nested +// class TestBuildGrpcRepresentationFile { +// +// private final IncomingFile file = IncomingFileTestFactory.create(); +// +// @BeforeEach +// void mock() { +// when(incomingFileMapper.toRepresentationFile(any())).thenReturn(GrpcRepresentationFileTestFactory.create()); +// } +// +// @Test +// void shouldCallIncomingFileMapper() { +// service.buildGrpcRepresentationFile(file); +// +// verify(incomingFileMapper).toRepresentationFile(file); +// } +// +// @Test +// void shouldReturnRepresentationMetadataRequest() { +// var result = service.buildGrpcRepresentationFile(file); +// +// assertThat(result).isEqualTo(GrpcRouteForwardingRequestTestFactory.createWithRepresentationMetadata()); +// } +// } +// +// @Nested +// class TestWaitForCompletion { +// +// @Mock +// private CompletableFuture<Void> future; +// +// @SneakyThrows +// @Test +// void shouldGetFromFuture() { +// waitForCompletion(); +// +// verify(future).get(2, TimeUnit.MINUTES); +// } +// +// @Nested +// class TestOnInterruptedException { +// +// private final InterruptedException exception = new InterruptedException(); +// +// @BeforeEach +// @SneakyThrows +// void mock() { +// when(future.get(anyLong(), any())).thenThrow(exception); +// } +// +// @Test +// void shouldThrowTechnicalException() { +// assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); +// } +// +// @Test +// void shouldInterruptThread() { +// try { +// waitForCompletion(); +// } catch (TechnicalException e) { +// // expected +// } +// +// assertThat(Thread.currentThread().isInterrupted()).isTrue(); +// } +// } +// +// @Nested +// class TestOnExecutionException { +// +// private final ExecutionException exception = new ExecutionException(new Exception()); +// +// @BeforeEach +// @SneakyThrows +// void mock() { +// when(future.get(anyLong(), any())).thenThrow(exception); +// } +// +// @Test +// void shouldThrowTechnicalException() { +// assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); +// } +// } +// +// @Nested +// class TestOnTimeoutException { +// +// private final TimeoutException exception = new TimeoutException(); +// +// @BeforeEach +// @SneakyThrows +// void mock() { +// when(future.get(anyLong(), any())).thenThrow(exception); +// } +// +// @Test +// void shouldThrowTechnicalException() { +// assertThrows(TechnicalException.class, TestWaitForCompletion.this::waitForCompletion); +// } +// } +// +// private void waitForCompletion() { +// service.waitForCompletion(future); +// } +// } +// +// @Nested +// class ForwardingResponseObserverTest { +// +// @Mock +// private CompletableFuture<Void> future; +// private ForwardingResponseObserver responseObserver; +// +// @BeforeEach +// void init() { +// responseObserver = new ForwardingResponseObserver(future); +// } +// +// @Test +// void shouldCompleteExceptionallyOnError() { +// var error = new Throwable(); +// +// responseObserver.onError(error); +// +// verify(future).completeExceptionally(error); +// } +// +// @Test +// void shouldCompleteOnCompleted() { +// responseObserver.onCompleted(); +// +// verify(future).complete(null); +// } +// } +//}