diff --git a/router/src/main/java/de/ozgcloud/eingang/router/ClosableStub.java b/router/src/main/java/de/ozgcloud/eingang/router/ClosableStub.java new file mode 100644 index 0000000000000000000000000000000000000000..5599172eed8316fdb56c14a43de2921325bbdf99 --- /dev/null +++ b/router/src/main/java/de/ozgcloud/eingang/router/ClosableStub.java @@ -0,0 +1,49 @@ +package de.ozgcloud.eingang.router; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import de.ozgcloud.eingang.common.errorhandling.TechnicalException; +import io.grpc.Channel; +import io.grpc.ManagedChannel; +import lombok.Builder; + +@Builder +class ClosableStub<T> implements ManagableStub<T> { + + private static final int SHUTDOWM_TIME = 10; + + private ManagedChannel channel; + private Function<Channel, T> creationFunction; + + private T stub; + + @Override + public T get() { + if (Objects.isNull(stub)) { + stub = creationFunction.apply(channel); + } + return stub; + } + + public void close() { + if (Objects.nonNull(stub)) { + shutdownChannel(); + stub = null; + } + } + + private void shutdownChannel() { + try { + channel.shutdown().awaitTermination(ClosableStub.SHUTDOWM_TIME, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new TechnicalException("Error shutting down grpc channel.", e); + } + } + + @Override + public boolean isShutdownable() { + return true; + } +} \ No newline at end of file diff --git a/router/src/main/java/de/ozgcloud/eingang/router/ConsistingStub.java b/router/src/main/java/de/ozgcloud/eingang/router/ConsistingStub.java new file mode 100644 index 0000000000000000000000000000000000000000..d77a046240e55163800bf7cb512a60dc0e2f6a86 --- /dev/null +++ b/router/src/main/java/de/ozgcloud/eingang/router/ConsistingStub.java @@ -0,0 +1,19 @@ +package de.ozgcloud.eingang.router; + +import lombok.Builder; + +@Builder +class ConsistingStub<T> implements ManagableStub<T> { + + private T stub; + + @Override + public T get() { + return stub; + } + + @Override + public boolean isShutdownable() { + return false; + } +} \ No newline at end of file diff --git a/router/src/main/java/de/ozgcloud/eingang/router/ManagableStub.java b/router/src/main/java/de/ozgcloud/eingang/router/ManagableStub.java new file mode 100644 index 0000000000000000000000000000000000000000..8ffa720b62ab5117f372ea79028fbe7fe95b1c57 --- /dev/null +++ b/router/src/main/java/de/ozgcloud/eingang/router/ManagableStub.java @@ -0,0 +1,8 @@ +package de.ozgcloud.eingang.router; + +interface ManagableStub<T> { + + T get(); + + boolean isShutdownable(); +} \ No newline at end of file diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java index 996bc649d7d78262422b8c63b854b8070e6c0ba5..c88208ab3b4c1b60c73db922604597e0cc02783f 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangManagerServerResolver.java @@ -79,15 +79,16 @@ public class VorgangManagerServerResolver { .findFirst().orElseThrow(() -> new AdapterConfigurationException("Cannot find Stub-Factory for GRPC-" + stubClass)); } - public VorgangServiceBlockingStub resolveVorgangServiceBlockingStubByOrganisationseinheitenId(Optional<String> organisationsEinheitId) { - return (VorgangServiceBlockingStub) createStub(organisationsEinheitId, vorgangStubFactory, VorgangServiceBlockingStub.class); + public ManagableStub<VorgangServiceBlockingStub> resolveVorgangServiceBlockingStubByOrganisationseinheitenId( + Optional<String> organisationsEinheitId) { + return (ManagableStub<VorgangServiceBlockingStub>) createStub(organisationsEinheitId, vorgangStubFactory, VorgangServiceBlockingStub.class); } - public BinaryFileServiceStub resolveBinaryFileServiceStubByOrganisationsEinheitId(Optional<String> organisationsEinheitId) { - return (BinaryFileServiceStub) createStub(organisationsEinheitId, binaryFileAsynStubFactory, BinaryFileServiceStub.class); + public ManagableStub<BinaryFileServiceStub> resolveBinaryFileServiceStubByOrganisationsEinheitId(Optional<String> organisationsEinheitId) { + return (ManagableStub<BinaryFileServiceStub>) createStub(organisationsEinheitId, binaryFileAsynStubFactory, BinaryFileServiceStub.class); } - AbstractStub<?> createStub(Optional<String> organisationsEinheitId, StubFactory stubFactory, Class<? extends AbstractStub<?>> stubClass) {// NOSONAR + ManagableStub<?> createStub(Optional<String> organisationsEinheitId, StubFactory stubFactory, Class<? extends AbstractStub<?>> stubClass) {// NOSONAR if (properties.getRoutingStrategy() == RoutingStrategy.ZUFI) { return createStubUsingZufi(organisationsEinheitId, stubFactory, stubClass); } else { @@ -95,17 +96,17 @@ public class VorgangManagerServerResolver { } } - AbstractStub<?> createStubUsingZufi(Optional<String> organisationsEinheitId, StubFactory stubFactory, + ManagableStub<?> createStubUsingZufi(Optional<String> organisationsEinheitId, StubFactory stubFactory, Class<? extends AbstractStub<?>> stubClass) { return null; } - AbstractStub<?> createStubByConfiguredChannels(Optional<String> organisationsEinheitId, StubFactory stubFactory, + ManagableStub<?> createStubByConfiguredChannels(Optional<String> organisationsEinheitId, StubFactory stubFactory, Class<? extends AbstractStub<?>> stubClass) { var channelName = getChannelName(organisationsEinheitId); var stub = stubFactory.createStub(stubClass, createChannelByName(channelName)); - - return applyStubTransformers(stub, channelName); + stub = applyStubTransformers(stub, channelName); + return ConsistingStub.builder().stub(stub).build(); } String getChannelName(Optional<String> organisationsEinheitId) { diff --git a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java index 54ee2075fe8827984a34b0dfec99c4a9cbec410f..b566b57f8894602c379f4e1699bae79e95ca30db 100644 --- a/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java +++ b/router/src/main/java/de/ozgcloud/eingang/router/VorgangRemoteService.java @@ -67,21 +67,40 @@ public class VorgangRemoteService { private VorgangManagerServerResolver vorgangManagerServerResolver; public String createVorgang(FormData formData, GrpcEingang eingang, Optional<String> organisationsEinheitenId) { - var vorgangManagerStub = vorgangManagerServerResolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitenId); - LOG.info("Connecting to vorgang-manager server " + vorgangManagerStub.getChannel().authority() + "; OrganisationsEinheitId: " + organisationsEinheitenId); + var vorgangServiceStub = getVorgangServiceStub(organisationsEinheitenId); + var binaryFileServiceStub = getBinaryFileServiceStub(organisationsEinheitenId); - return createVorgang(formData, eingang, vorgangManagerStub, getBinaryFileServiceStub(organisationsEinheitenId)); + logConnection(organisationsEinheitenId, vorgangServiceStub.get()); + + var vorgangId = createVorgang(formData, eingang, vorgangServiceStub.get(), binaryFileServiceStub.get()); + + finishStubConnections(List.of(vorgangServiceStub, binaryFileServiceStub)); + + return vorgangId; + } + + void logConnection(Optional<String> organisationsEinheitenId, VorgangServiceBlockingStub vorgangStub) { + LOG.info("Connecting to vorgang-manager server " + vorgangStub.getChannel().authority() + "; OrganisationsEinheitId: " + + organisationsEinheitenId); } - public String createVorgang(FormData formData, GrpcEingang eingang, VorgangServiceBlockingStub remoteStub, - BinaryFileServiceStub remoteAsyncStub) { - return new VorgangCreator(formData, eingang, remoteStub, remoteAsyncStub).create(); + private ManagableStub<VorgangServiceBlockingStub> getVorgangServiceStub(Optional<String> organisationsEinheitenId) { + return vorgangManagerServerResolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitenId); } - private BinaryFileServiceStub getBinaryFileServiceStub(Optional<String> organisationsEinheitenId) { + private ManagableStub<BinaryFileServiceStub> getBinaryFileServiceStub(Optional<String> organisationsEinheitenId) { return vorgangManagerServerResolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(organisationsEinheitenId); } + public String createVorgang(FormData formData, GrpcEingang eingang, VorgangServiceBlockingStub vorgangStub, + BinaryFileServiceStub binaryFileStub) { + return new VorgangCreator(formData, eingang, vorgangStub, binaryFileStub).create(); + } + + void finishStubConnections(List<ManagableStub<?>> stubs) { + stubs.stream().filter(ManagableStub::isShutdownable).map(ClosableStub.class::cast).forEach(ClosableStub::close); + } + @RequiredArgsConstructor public class VorgangCreator { diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java index f4274268163ca9745e5e3a4a325c21578b335ac6..23daf33f29dcf1f011a88e94f160fb08154ae5ea 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangManagerServerResolverTest.java @@ -96,7 +96,7 @@ class VorgangManagerServerResolverTest { class TestResolveVorgangManagerServiceStubByOrganisationsEinheitenId { @Mock - private VorgangServiceBlockingStub stub; + private ManagableStub<VorgangServiceBlockingStub> stub; private final Optional<String> organisationsEinheitenId = Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); @@ -113,13 +113,13 @@ class VorgangManagerServerResolverTest { } @Test - void shouldReturnManageableStub() { + void shouldReturnStub() { var createdStub = resolveStub(); assertThat(createdStub).isEqualTo(stub); } - private VorgangServiceBlockingStub resolveStub() { + private ManagableStub<VorgangServiceBlockingStub> resolveStub() { return resolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitenId); } } @@ -129,7 +129,7 @@ class VorgangManagerServerResolverTest { class TestResolveBinaryFileServiceStubByOrganisationsEinheitenId { @Mock - private BinaryFileServiceStub stub; + private ManagableStub<BinaryFileServiceStub> stub; private final Optional<String> organisationsEinheitenId = Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); @@ -146,13 +146,13 @@ class VorgangManagerServerResolverTest { } @Test - void shouldReturnManageableStub() { + void shouldStub() { var createdStub = resolveStub(); assertThat(createdStub).isEqualTo(stub); } - private BinaryFileServiceStub resolveStub() { + private ManagableStub<BinaryFileServiceStub> resolveStub() { return resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(organisationsEinheitenId); } } @@ -162,7 +162,7 @@ class VorgangManagerServerResolverTest { class TestCreateStub { @Mock - private AbstractStub<?> createdStub; + private ManagableStub<?> createdStub; private Class<? extends AbstractStub<?>> stubClass = VorgangServiceBlockingStub.class; private Optional<String> organisationsEinheitenId = Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID); @@ -217,7 +217,7 @@ class VorgangManagerServerResolverTest { } } - private AbstractStub<?> createStub() { + private ManagableStub<?> createStub() { return resolver.createStub(organisationsEinheitenId, stubFactory, stubClass); } } @@ -230,6 +230,8 @@ class VorgangManagerServerResolverTest { private Channel channel; @Mock private StubFactory stubFactory; + @Mock + private AbstractStub<?> createdStub; private Class<? extends AbstractStub<?>> stubClass = VorgangServiceBlockingStub.class; @@ -238,6 +240,7 @@ class VorgangManagerServerResolverTest { doReturn(VorgangManagerListPropertiesTestFactory.CHANNEL_NAME).when(resolver).getChannelName(any()); doReturn(channel).when(resolver).createChannelByName(any()); setProperties(VorgangManagerListPropertiesTestFactory.createForSingleRouting()); + doReturn(createdStub).when(resolver).applyStubTransformers(any(), any()); } @Test @@ -261,7 +264,14 @@ class VorgangManagerServerResolverTest { verify(stubFactory).createStub(eq(stubClass), any()); } - private AbstractStub<?> createStubByConfiguredChannels() { + @Test + void shouldReturnStub() { + var stub = createStubByConfiguredChannels(); + + assertThat(stub.get()).isEqualTo(createdStub); + } + + private ManagableStub<?> createStubByConfiguredChannels() { return resolver.createStubByConfiguredChannels(Optional.of(VorgangManagerListPropertiesTestFactory.ORGANISATIONSEINHEIT_ID), stubFactory, stubClass); } diff --git a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java index 60206de34962325a9a4b66061f7f65617233cec3..a5d7ad6c3d15c320a7149e30355ebd1bec06029b 100644 --- a/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java +++ b/router/src/test/java/de/ozgcloud/eingang/router/VorgangRemoteServiceTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.*; import java.io.InputStream; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -37,6 +38,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -45,6 +47,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender; import de.ozgcloud.common.errorhandling.TechnicalException; @@ -54,6 +57,7 @@ import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.IncomingFileGroup; import de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory; +import de.ozgcloud.eingang.common.formdata.ZustaendigeStelleTestFactory; import de.ozgcloud.eingang.router.VorgangRemoteService.VorgangCreator; import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub; import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileMetaData; @@ -70,14 +74,11 @@ import lombok.SneakyThrows; class VorgangRemoteServiceTest { + @Spy @InjectMocks private VorgangRemoteService remoteService; @Mock - private final VorgangServiceBlockingStub vorgangStub = VorgangManagerServerResolverTestFactory.createVorgangBlockingStub(); - @Mock - private final BinaryFileServiceStub binaryFileStub = VorgangManagerServerResolverTestFactory.createBinaryFileStub(); - @Mock - private GrpcEingangMapper eingangMapper; + private VorgangManagerServerResolver resolver; private VorgangCreator vorgangCreator; @@ -87,286 +88,398 @@ class VorgangRemoteServiceTest { .addRepresentations(GrpcIncomingFileTestFactory.create()) .build(); private final String vorgangId = UUID.randomUUID().toString(); - private String fileId = "42"; - - @BeforeEach - void init() { - vorgangCreator = spy(remoteService.new VorgangCreator(formData, eingang, vorgangStub, binaryFileStub)); - } + private final String fileId = "42"; + @DisplayName("Create vorgang") @Nested class TestCreateVorgang { @Mock - private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver; - @Captor - private ArgumentCaptor<GrpcCreateVorgangRequest> requestCaptor; - @Captor - private ArgumentCaptor<GrpcFinishCreationRequest> finishRequestCaptor; + private ManagableStub<VorgangServiceBlockingStub> managableVorgangServiceStub; + @Mock + private VorgangServiceBlockingStub vorgangServiceStub; - private final GrpcCreateVorgangResponse createVorgangResponse = GrpcCreateVorgangResponse.newBuilder().setVorgangId(vorgangId).build(); - private final GrpcFinishCreationResponse finishResponse = GrpcFinishCreationResponse.newBuilder().setMessage("OK").build(); + @Mock + private ManagableStub<BinaryFileServiceStub> managableBinaryFileServiceStub; + @Mock + private BinaryFileServiceStub binaryFileServiceStub; - @BeforeEach - void init() { - when(vorgangStub.startCreation(any())).thenReturn(createVorgangResponse); - when(vorgangStub.finishCreation(any())).thenReturn(finishResponse); - doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any()); - doReturn(GrpcFinishCreationRequest.newBuilder().build()).when(vorgangCreator).buildFinishCreationRequest(); - } + private final Optional<String> organisationsEinheitId = Optional.of(ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID); - @Test - void shouldStartCreation() { - createVorgang(); + @BeforeEach + void mock() { + doReturn(vorgangId).when(remoteService).createVorgang(any(), any(), any(), any()); - verify(vorgangStub).startCreation(any(GrpcCreateVorgangRequest.class)); - } + when(resolver.resolveVorgangServiceBlockingStubByOrganisationseinheitenId(any())).thenReturn(managableVorgangServiceStub); + when(managableVorgangServiceStub.get()).thenReturn(vorgangServiceStub); - @Test - void shouldStartCreationWithEmptyAttachmetns() { - createVorgang(); + when(resolver.resolveBinaryFileServiceStubByOrganisationsEinheitId(any())).thenReturn(managableBinaryFileServiceStub); + when(managableBinaryFileServiceStub.get()).thenReturn(binaryFileServiceStub); - verify(vorgangStub).startCreation(requestCaptor.capture()); - assertThat(requestCaptor.getValue().getEingang().getAttachmentsList()).isEmpty(); + doNothing().when(remoteService).logConnection(any(), any()); + doNothing().when(remoteService).finishStubConnections(any()); } @Test - void shouldStartCreationWithEmptyRepresentations() { + void shouldGetVorgangService() { createVorgang(); - verify(vorgangStub).startCreation(requestCaptor.capture()); - assertThat(requestCaptor.getValue().getEingang().getRepresentationsList()).isEmpty(); + verify(resolver).resolveVorgangServiceBlockingStubByOrganisationseinheitenId(organisationsEinheitId); } @Test - void shouldCallUploadAttachments() { + void shouldGetBinaryFileService() { createVorgang(); - verify(vorgangCreator).uploadAttachments(); + verify(resolver).resolveBinaryFileServiceStubByOrganisationsEinheitId(organisationsEinheitId); } @Test - void shouldCallUploadRepresentations() { + void shouldCreateVorgang() { createVorgang(); - verify(vorgangCreator).uploadRepresentations(); + verify(remoteService).createVorgang(formData, eingang, vorgangServiceStub, binaryFileServiceStub); } @Test - void shouldFinishCreation() { + void shouldFinishStubConnection() { createVorgang(); - verify(vorgangStub).finishCreation(finishRequestCaptor.capture()); - assertThat(finishRequestCaptor.getValue()).isInstanceOf(GrpcFinishCreationRequest.class); + verify(remoteService).finishStubConnections(List.of(managableVorgangServiceStub, managableBinaryFileServiceStub)); } @Test void shouldReturnVorgangId() { - var result = createVorgang(); + var created = createVorgang(); + + assertThat(created).isEqualTo(vorgangId); - assertThat(result).isEqualTo(vorgangId); } private String createVorgang() { - return vorgangCreator.create(); + return remoteService.createVorgang(formData, eingang, organisationsEinheitId); } } + @DisplayName("Finish stub connections") @Nested - class TestUploadAttachments { + class TestFinishStubConnections { + + @Mock + private ClosableStub<VorgangServiceBlockingStub> closableStub; @BeforeEach - void mockFileId() { - doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any()); + void mock() { + when(closableStub.isShutdownable()).thenReturn(true); + doNothing().when(closableStub).close(); } @Test - void shouldCallUploadIncomingFile() { - vorgangCreator.uploadAttachments(); + void shouldCheckIfSubIsShutdownable() { + remoteService.finishStubConnections(List.of(closableStub)); - verify(vorgangCreator, times(2)).uploadIncomingFile(any(IncomingFile.class)); + verify(closableStub).isShutdownable(); } @Test - void shouldSetFileId() { - var uploadedAttachments = vorgangCreator.uploadAttachments(); + void shouldShutDownChannelForClosableStubs() { + remoteService.finishStubConnections(List.of(closableStub)); - assertThat(uploadedAttachments.get(0).getFiles().get(0).getId()).isEqualTo(fileId); + verify((ClosableStub) closableStub).close(); } } + @DisplayName("VorgangCreator") @Nested - class TestUploadRepresentations { + class TestVorgangCreator { + + @Mock + private final VorgangServiceBlockingStub vorgangStub = VorgangManagerServerResolverTestFactory.createVorgangBlockingStub(); + @Mock + private final BinaryFileServiceStub binaryFileStub = VorgangManagerServerResolverTestFactory.createBinaryFileStub(); + @Mock + private GrpcEingangMapper eingangMapper; @BeforeEach - void mockFileId() { - doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any()); + void init() { + vorgangCreator = spy(remoteService.new VorgangCreator(formData, eingang, vorgangStub, binaryFileStub)); } - @Test - void shouldCallUploadIncomingFile() { - vorgangCreator.uploadRepresentations(); + @Nested + class TestCreateVorgang { - verify(vorgangCreator).uploadIncomingFile(any(IncomingFile.class)); - } + @Mock + private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver; + @Captor + private ArgumentCaptor<GrpcCreateVorgangRequest> requestCaptor; + @Captor + private ArgumentCaptor<GrpcFinishCreationRequest> finishRequestCaptor; - @Test - void shouldSetFileId() { - var uploadedRepresentations = vorgangCreator.uploadRepresentations(); + private final GrpcCreateVorgangResponse createVorgangResponse = GrpcCreateVorgangResponse.newBuilder().setVorgangId(vorgangId).build(); + private final GrpcFinishCreationResponse finishResponse = GrpcFinishCreationResponse.newBuilder().setMessage("OK").build(); - assertThat(uploadedRepresentations.get(0).getId()).isEqualTo(fileId); - } - } + @BeforeEach + void init() { + when(vorgangStub.startCreation(any())).thenReturn(createVorgangResponse); + when(vorgangStub.finishCreation(any())).thenReturn(finishResponse); + doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any()); + doReturn(GrpcFinishCreationRequest.newBuilder().build()).when(vorgangCreator).buildFinishCreationRequest(); + } - @Nested - class TestBuildMetaDataRequest { + @Test + void shouldStartCreation() { + createVorgang(); - @BeforeEach - void mockMapper() { - doReturn(vorgangId).when(vorgangCreator).getVorgangId(); - } + verify(vorgangStub).startCreation(any(GrpcCreateVorgangRequest.class)); + } - @Test - void shouldContainsContext() { - var metaData = buildMetaData(); + @Test + void shouldStartCreationWithEmptyAttachmetns() { + createVorgang(); - assertThat(metaData.getContext().getClient()).isEqualTo(VorgangRemoteService.VorgangCreator.CALL_CONTEXT_CLIENT); - } + verify(vorgangStub).startCreation(requestCaptor.capture()); + assertThat(requestCaptor.getValue().getEingang().getAttachmentsList()).isEmpty(); + } - @Test - void shouldContainsVorgangId() { - var metaData = buildMetaData(); + @Test + void shouldStartCreationWithEmptyRepresentations() { + createVorgang(); - assertThat(metaData.getVorgangId()).isEqualTo(vorgangId); - } + verify(vorgangStub).startCreation(requestCaptor.capture()); + assertThat(requestCaptor.getValue().getEingang().getRepresentationsList()).isEmpty(); + } - @Test - void shouldContainsField() { - var metaData = buildMetaData(); + @Test + void shouldCallUploadAttachments() { + createVorgang(); - assertThat(metaData.getField()).isEqualTo(VorgangRemoteService.VorgangCreator.VORGANG_ATTACHMENT_FIELD); - } + verify(vorgangCreator).uploadAttachments(); + } - @Test - void shouldContainsContentType() { - var metaData = buildMetaData(); + @Test + void shouldCallUploadRepresentations() { + createVorgang(); - assertThat(metaData.getContentType()).isEqualTo(IncomingFileTestFactory.CONTENT_TYPE); - } + verify(vorgangCreator).uploadRepresentations(); + } - @Test - void shouldContainsSize() { - var metaData = buildMetaData(); + @Test + void shouldFinishCreation() { + createVorgang(); - assertThat(metaData.getSize()).isEqualTo(IncomingFileTestFactory.SIZE); - } + verify(vorgangStub).finishCreation(finishRequestCaptor.capture()); + assertThat(finishRequestCaptor.getValue()).isInstanceOf(GrpcFinishCreationRequest.class); + } - @Test - void shouldContainsFileName() { - var metaData = buildMetaData(); + @Test + void shouldReturnVorgangId() { + var result = createVorgang(); - assertThat(metaData.getFileName()).isEqualTo(IncomingFileTestFactory.NAME); - } + assertThat(result).isEqualTo(vorgangId); + } - private GrpcUploadBinaryFileMetaData buildMetaData() { - return vorgangCreator.buildMetaDataRequest(IncomingFileTestFactory.create()).getMetadata(); + private String createVorgang() { + return vorgangCreator.create(); + } } - } - @Nested - class TestWaitUntilFutureToComplete { + @Nested + class TestUploadAttachments { - @Mock - private FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> sender; + @BeforeEach + void mockFileId() { + doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any()); + } - @Mock - private CompletableFuture<GrpcUploadBinaryFileResponse> streamFuture; + @Test + void shouldCallUploadIncomingFile() { + vorgangCreator.uploadAttachments(); - @Mock - private InputStream inputStream; + verify(vorgangCreator, times(2)).uploadIncomingFile(any(IncomingFile.class)); + } - @BeforeEach - void initSender() { - when(sender.getResultFuture()).thenReturn(streamFuture); - } + @Test + void shouldSetFileId() { + var uploadedAttachments = vorgangCreator.uploadAttachments(); - @Test - void shouldNotThrowException() { - assertDoesNotThrow(() -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream)); + assertThat(uploadedAttachments.get(0).getFiles().get(0).getId()).isEqualTo(fileId); + } } - @ParameterizedTest - @ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class }) - void shouldRethrowAsTechnicalException(Class<Exception> exception) - throws InterruptedException, ExecutionException, TimeoutException { - doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class)); + @Nested + class TestUploadRepresentations { - assertThrows(TechnicalException.class, () -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream)); - } + @BeforeEach + void mockFileId() { + doReturn(fileId).when(vorgangCreator).uploadIncomingFile(any()); + } - @ParameterizedTest - @ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class }) - @SneakyThrows - void shouldCloseFileContentStreamOnException(Class<Exception> exception) { - doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class)); + @Test + void shouldCallUploadIncomingFile() { + vorgangCreator.uploadRepresentations(); - try { - vorgangCreator.waitUntilFutureToComplete(sender, inputStream); - } catch (Exception e) { - // ignored + verify(vorgangCreator).uploadIncomingFile(any(IncomingFile.class)); + } + + @Test + void shouldSetFileId() { + var uploadedRepresentations = vorgangCreator.uploadRepresentations(); + + assertThat(uploadedRepresentations.get(0).getId()).isEqualTo(fileId); } - verify(inputStream).close(); } - @Test - @SneakyThrows - void shouldCloseFileContent() { - try { - vorgangCreator.waitUntilFutureToComplete(sender, inputStream); - } catch (Exception e) { - // ignored + @Nested + class TestBuildMetaDataRequest { + + @BeforeEach + void mockMapper() { + doReturn(vorgangId).when(vorgangCreator).getVorgangId(); } - verify(inputStream).close(); - } - } + @Test + void shouldContainsContext() { + var metaData = buildMetaData(); - @Nested - class TestBuildFinishCreationRequest { + assertThat(metaData.getContext().getClient()).isEqualTo(VorgangRemoteService.VorgangCreator.CALL_CONTEXT_CLIENT); + } - private final IncomingFileGroup attachment = IncomingFileGroupTestFactory.create(); - private final IncomingFile representation = IncomingFileTestFactory.create(); + @Test + void shouldContainsVorgangId() { + var metaData = buildMetaData(); - @BeforeEach - void mock() { - doReturn(vorgangId).when(vorgangCreator).getVorgangId(); - doReturn(List.of(attachment)).when(vorgangCreator).getUploadedAttachments(); - doReturn(List.of(representation)).when(vorgangCreator).getUploadedRepresentations(); - } + assertThat(metaData.getVorgangId()).isEqualTo(vorgangId); + } - @Test - void shouldContainsVorgangId() { - var request = buildFinishCreationRequest(); + @Test + void shouldContainsField() { + var metaData = buildMetaData(); - assertThat(request.getVorgangId()).isEqualTo(vorgangId); - } + assertThat(metaData.getField()).isEqualTo(VorgangRemoteService.VorgangCreator.VORGANG_ATTACHMENT_FIELD); + } - @Test - void shouldContainsAttachmentWithoutContent() { - var request = buildFinishCreationRequest(); + @Test + void shouldContainsContentType() { + var metaData = buildMetaData(); + + assertThat(metaData.getContentType()).isEqualTo(IncomingFileTestFactory.CONTENT_TYPE); + } + + @Test + void shouldContainsSize() { + var metaData = buildMetaData(); - assertThat(request.getAttachments(0).getFiles(0).getContent()).isEmpty(); + assertThat(metaData.getSize()).isEqualTo(IncomingFileTestFactory.SIZE); + } + + @Test + void shouldContainsFileName() { + var metaData = buildMetaData(); + + assertThat(metaData.getFileName()).isEqualTo(IncomingFileTestFactory.NAME); + } + + private GrpcUploadBinaryFileMetaData buildMetaData() { + return vorgangCreator.buildMetaDataRequest(IncomingFileTestFactory.create()).getMetadata(); + } } - @Test - void shouldContainsRepresentationsWithoutContent() { - var request = buildFinishCreationRequest(); + @Nested + class TestWaitUntilFutureToComplete { + + @Mock + private FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> sender; - assertThat(request.getRepresentations(0).getContent()).isEmpty(); + @Mock + private CompletableFuture<GrpcUploadBinaryFileResponse> streamFuture; + + @Mock + private InputStream inputStream; + + @BeforeEach + void initSender() { + when(sender.getResultFuture()).thenReturn(streamFuture); + } + + @Test + void shouldNotThrowException() { + assertDoesNotThrow(() -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream)); + } + + @ParameterizedTest + @ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class }) + void shouldRethrowAsTechnicalException(Class<Exception> exception) + throws InterruptedException, ExecutionException, TimeoutException { + doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class)); + + assertThrows(TechnicalException.class, () -> vorgangCreator.waitUntilFutureToComplete(sender, inputStream)); + } + + @ParameterizedTest + @ValueSource(classes = { InterruptedException.class, ExecutionException.class, TimeoutException.class }) + @SneakyThrows + void shouldCloseFileContentStreamOnException(Class<Exception> exception) { + doThrow(exception).when(streamFuture).get(anyLong(), any(TimeUnit.class)); + + waitUntilFutureToComplete(); + + verify(inputStream).close(); + } + + @Test + @SneakyThrows + void shouldCloseFileContent() { + waitUntilFutureToComplete(); + + verify(inputStream).close(); + } + + private void waitUntilFutureToComplete() { + try { + vorgangCreator.waitUntilFutureToComplete(sender, inputStream); + } catch (Exception e) { + // ignored + } + } } - private GrpcFinishCreationRequest buildFinishCreationRequest() { - return vorgangCreator.buildFinishCreationRequest(); + @Nested + class TestBuildFinishCreationRequest { + + private final IncomingFileGroup attachment = IncomingFileGroupTestFactory.create(); + private final IncomingFile representation = IncomingFileTestFactory.create(); + + @BeforeEach + void mock() { + doReturn(vorgangId).when(vorgangCreator).getVorgangId(); + doReturn(List.of(attachment)).when(vorgangCreator).getUploadedAttachments(); + doReturn(List.of(representation)).when(vorgangCreator).getUploadedRepresentations(); + } + + @Test + void shouldContainsVorgangId() { + var request = buildFinishCreationRequest(); + + assertThat(request.getVorgangId()).isEqualTo(vorgangId); + } + + @Test + void shouldContainsAttachmentWithoutContent() { + var request = buildFinishCreationRequest(); + + assertThat(request.getAttachments(0).getFiles(0).getContent()).isEmpty(); + } + + @Test + void shouldContainsRepresentationsWithoutContent() { + var request = buildFinishCreationRequest(); + + assertThat(request.getRepresentations(0).getContent()).isEmpty(); + } + + private GrpcFinishCreationRequest buildFinishCreationRequest() { + return vorgangCreator.buildFinishCreationRequest(); + } } } } \ No newline at end of file