Skip to content
Snippets Groups Projects
Commit 66902a1b authored by OZGCloud's avatar OZGCloud
Browse files

OZG-6810 extend tests

parent 736e2de0
Branches
Tags
No related merge requests found
......@@ -40,8 +40,9 @@ import net.devh.boot.grpc.client.inject.GrpcClient;
@Configuration
public class DocumentManagerConfiguration {
private static final String GRPC_USER_MANAGER_NAME = "user-manager";
private static final String GRPC_COMMAND_MANAGER_NAME = "command-manager";
public static final String GRPC_USER_MANAGER_NAME = "user-manager";
public static final String GRPC_COMMAND_MANAGER_NAME = "command-manager";
public static final String GRPC_VORGANG_MANAGER_NAME = "vorgang-manager";
public static final String COMMAND_SERVICE_NAME = "document_OzgCloudCommandService";
public static final String USER_PROFILE_SERVICE_NAME = "document_OzgCloudUserProfileService";
......
......@@ -15,18 +15,17 @@ import org.springframework.stereotype.Service;
import com.google.protobuf.ByteString;
import de.ozgcloud.document.DocumentManagerConfiguration;
import de.ozgcloud.document.bescheid.BescheidCallContextAttachingInterceptor;
import de.ozgcloud.document.bescheid.BescheidResponse;
import de.ozgcloud.common.binaryfile.FileId;
import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils;
import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender;
import de.ozgcloud.common.errorhandling.TechnicalException;
import de.ozgcloud.document.DocumentManagerConfiguration;
import de.ozgcloud.document.bescheid.BescheidCallContextAttachingInterceptor;
import de.ozgcloud.document.bescheid.BescheidResponse;
import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileMetaData;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileRequest;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileResponse;
import de.ozgcloud.vorgang.grpc.command.GrpcCallContext;
import io.grpc.stub.CallStreamObserver;
import io.grpc.stub.StreamObserver;
import lombok.NonNull;
......@@ -37,10 +36,9 @@ import net.devh.boot.grpc.client.inject.GrpcClient;
@RequiredArgsConstructor
class BinaryFileRemoteService {
private static final String CALL_CONTEXT_CLIENT = "bescheid-manager";
private static final String VORGANG_ATTACHMENT_FIELD = "bescheid";
static final String VORGANG_ATTACHMENT_FIELD = "bescheid";
@GrpcClient("vorgang-manager")
@GrpcClient(DocumentManagerConfiguration.GRPC_VORGANG_MANAGER_NAME)
private final BinaryFileServiceStub binaryFileRemoteStub;
@Qualifier(DocumentManagerConfiguration.CALL_CONTEXT_CLIENT_INTERCEPTOR_NAME)
private final BescheidCallContextAttachingInterceptor callContextInterceptor;
......@@ -58,7 +56,7 @@ class BinaryFileRemoteService {
}
}
private InputStream openFile(File file) {
InputStream openFile(File file) {
try {
return new FileInputStream(file);
} catch (FileNotFoundException e) {
......@@ -66,11 +64,9 @@ class BinaryFileRemoteService {
}
}
private GrpcUploadBinaryFileRequest buildMetaDataRequest(BescheidResponse bescheid) {
GrpcUploadBinaryFileRequest buildMetaDataRequest(BescheidResponse bescheid) {
return GrpcUploadBinaryFileRequest.newBuilder()
.setMetadata(GrpcUploadBinaryFileMetaData.newBuilder()
// TODO remove context - check why needed!
.setContext(GrpcCallContext.newBuilder().setClient(CALL_CONTEXT_CLIENT).build())
.setVorgangId(bescheid.getVorgangId().toString())
.setField(VORGANG_ATTACHMENT_FIELD)
.setContentType(bescheid.getContentType())
......@@ -80,11 +76,11 @@ class BinaryFileRemoteService {
.build();
}
private GrpcUploadBinaryFileRequest buildChunkRequest(byte[] bytes, Integer length) {
GrpcUploadBinaryFileRequest buildChunkRequest(byte[] bytes, Integer length) {
return GrpcUploadBinaryFileRequest.newBuilder().setFileContent((ByteString.copyFrom(bytes, 0, length))).build();
}
private CallStreamObserver<GrpcUploadBinaryFileRequest> buildCallStreamObserver(
CallStreamObserver<GrpcUploadBinaryFileRequest> buildCallStreamObserver(
StreamObserver<GrpcUploadBinaryFileResponse> responseObserver) {
return (CallStreamObserver<GrpcUploadBinaryFileRequest>) binaryFileRemoteStub.withInterceptors(callContextInterceptor)
.uploadBinaryFileAsStream(responseObserver);
......
/*
* Copyright (C) 2024 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.document.bescheid.binaryfile;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.io.InputStream;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.AfterEach;
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;
import org.junit.jupiter.params.provider.ValueSource;
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.FileId;
import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils;
import de.ozgcloud.common.errorhandling.TechnicalException;
import de.ozgcloud.document.bescheid.BescheidCallContextAttachingInterceptor;
import de.ozgcloud.document.bescheid.BescheidResponse;
import de.ozgcloud.document.bescheid.BescheidResponseTestFactory;
import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileRequest;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileResponse;
import io.grpc.stub.CallStreamObserver;
import io.grpc.stub.StreamObserver;
import lombok.SneakyThrows;
class BinaryFileRemoteServiceTest {
@Spy
@InjectMocks
private BinaryFileRemoteService remoteService;
@Mock
private BinaryFileServiceStub binaryFileServiceStub;
@Mock
private BescheidCallContextAttachingInterceptor callContextInterceptor;
@Mock
private StreamObserver<GrpcUploadBinaryFileResponse> responseObserver;
@Mock
private GrpcUploadBinaryFileResponse grpcUploadResponse;
@Mock
private GrpcFileUploadUtils.FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> initialisedFileSender;
@Mock
private InputStream inputStream;
@Nested
class TestUploadBescheidFile {
private static final BescheidResponse BESCHEID_RESPONSE = BescheidResponseTestFactory.create();
private static final FileId FILE_ID = FileId.createNew();
@Mock
private GrpcFileUploadUtils.FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> createdFileSender;
@Mock
private GrpcFileUploadUtils.FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> fileSenderWithMetadata;
@Mock
private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver;
@Mock
private GrpcUploadBinaryFileRequest grpcUploadRequest;
@Captor
private ArgumentCaptor<BiFunction<byte[], Integer, GrpcUploadBinaryFileRequest>> buildChunkRequestCaptor;
@Captor
private ArgumentCaptor<Function<StreamObserver<GrpcUploadBinaryFileResponse>, CallStreamObserver<GrpcUploadBinaryFileRequest>>> buildCallStreamObserverCaptor;
private MockedStatic<GrpcFileUploadUtils> uploadUtilsMock;
@BeforeEach
void init() {
doReturn(inputStream).when(remoteService).openFile(any());
doReturn(grpcUploadResponse).when(remoteService).waitUntilFutureToComplete(any(), any());
when(grpcUploadResponse.getFileId()).thenReturn(FILE_ID.toString());
uploadUtilsMock = mockStatic(GrpcFileUploadUtils.class);
when(createdFileSender.withMetaData(any())).thenReturn(fileSenderWithMetadata);
when(fileSenderWithMetadata.send()).thenReturn(initialisedFileSender);
uploadUtilsMock.when(() -> GrpcFileUploadUtils.createSender(any(), any(), any())).thenReturn(createdFileSender);
}
@AfterEach
void cleanup() {
uploadUtilsMock.close();
}
@Test
void shouldCallOpenFile() {
uploadBescheidFile();
verify(remoteService).openFile(BescheidResponseTestFactory.BESCHEID_FILE);
}
@Test
void shouldCallCreateSender() {
uploadBescheidFile();
uploadUtilsMock.verify(() -> GrpcFileUploadUtils.createSender(buildChunkRequestCaptor.capture(), eq(inputStream),
buildCallStreamObserverCaptor.capture()));
verifyCallBuildChunkRequest();
verifyCallBuildCallStreamObserver();
}
@Test
void shouldCallBuildMetaDataRequest() {
uploadBescheidFile();
verify(remoteService).buildMetaDataRequest(BESCHEID_RESPONSE);
}
@Test
void shouldCallWithMetaData() {
doReturn(grpcUploadRequest).when(remoteService).buildMetaDataRequest(any());
uploadBescheidFile();
verify(createdFileSender).withMetaData(grpcUploadRequest);
}
@Test
void shouldCallSend() {
uploadBescheidFile();
verify(fileSenderWithMetadata).send();
}
@Test
void shouldCallWaitUntilFutureToComplete() {
uploadBescheidFile();
verify(remoteService).waitUntilFutureToComplete(initialisedFileSender, inputStream);
}
@Test
void shouldReturnFileId() {
var result = uploadBescheidFile();
assertThat(result).isEqualTo(FILE_ID);
}
private FileId uploadBescheidFile() {
return remoteService.uploadBescheidFile(BESCHEID_RESPONSE);
}
private void verifyCallBuildChunkRequest() {
doReturn(grpcUploadRequest).when(remoteService).buildChunkRequest(any(), any());
var bytes = new byte[1];
var length = 1;
buildChunkRequestCaptor.getValue().apply(bytes, length);
verify(remoteService).buildChunkRequest(bytes, length);
}
private void verifyCallBuildCallStreamObserver() {
doReturn(requestObserver).when(remoteService).buildCallStreamObserver(any());
buildCallStreamObserverCaptor.getValue().apply(responseObserver);
verify(remoteService).buildCallStreamObserver(responseObserver);
}
}
@Nested
class TestOpenFile {
@Test
void shouldReturnInputStream() {
var result = remoteService.openFile(BescheidResponseTestFactory.BESCHEID_FILE);
assertThat(result).hasBinaryContent(BescheidResponseTestFactory.BESCHEID_FILE_NAME.getBytes());
}
}
@Nested
class TestBuildMetaDataRequest {
@Test
void shouldReturnGrpcUploadBinaryFileRequest() {
var requestMetadata = GrpcUploadBinaryFileMetaDataTestFactory.createBuilder().setField(BinaryFileRemoteService.VORGANG_ATTACHMENT_FIELD)
.build();
var result = remoteService.buildMetaDataRequest(BescheidResponseTestFactory.create());
assertThat(result.getMetadata()).usingRecursiveComparison().isEqualTo(requestMetadata);
assertThat(result.getFileContent()).isEmpty();
}
}
@Nested
class TestBuildChunkRequest {
@Test
void shouldSetFileContent() {
var bytes = BescheidResponseTestFactory.BESCHEID_FILE_NAME.getBytes();
var length = BescheidResponseTestFactory.BESCHEID_FILE_NAME.length();
var result = remoteService.buildChunkRequest(bytes, length);
assertThat(result.getFileContent().toStringUtf8()).isEqualTo(BescheidResponseTestFactory.BESCHEID_FILE_NAME);
}
}
@Nested
class TestBuildCallStreamObserver {
@Mock
private BinaryFileServiceStub binaryFileServiceStubWithInterceptor;
@BeforeEach
void init() {
when(binaryFileServiceStub.withInterceptors(callContextInterceptor)).thenReturn(binaryFileServiceStubWithInterceptor);
}
@Test
void shouldSetInterceptor() {
buildCallStreamObserver();
verify(binaryFileServiceStub).withInterceptors(callContextInterceptor);
}
@Test
void shouldCallUploadBinaryFileAsStream() {
buildCallStreamObserver();
verify(binaryFileServiceStubWithInterceptor).uploadBinaryFileAsStream(responseObserver);
}
private CallStreamObserver<GrpcUploadBinaryFileRequest> buildCallStreamObserver() {
return remoteService.buildCallStreamObserver(responseObserver);
}
}
@Nested
class TestWaitUntilFutureToComplete {
@Mock
private GrpcUploadBinaryFileResponse grpcUploadResponse;
@Mock
private CompletableFuture<GrpcUploadBinaryFileResponse> responseFuture;
@BeforeEach
void init() {
when(initialisedFileSender.getResultFuture()).thenReturn(responseFuture);
}
@Nested
class TestOnSuccess {
@SneakyThrows
@BeforeEach
void init() {
when(responseFuture.get(anyLong(), any())).thenReturn(grpcUploadResponse);
}
@Test
void shouldReturnResponse() {
var result = waitUntilFutureToComplete();
assertThat(result).isSameAs(grpcUploadResponse);
}
@Test
void shouldCloseStream() {
try (var ioUtilsMock = mockStatic(IOUtils.class)) {
waitUntilFutureToComplete();
ioUtilsMock.verify(() -> IOUtils.closeQuietly(inputStream));
}
}
}
@Nested
class TestOnInterruptedException {
@Mock
private InterruptedException exception;
@BeforeEach
void init() throws ExecutionException, InterruptedException, TimeoutException {
when(responseFuture.get(anyLong(), any())).thenThrow(exception);
}
@Test
void shouldCallCancelOnError() {
assertThrows(TechnicalException.class, TestWaitUntilFutureToComplete.this::waitUntilFutureToComplete);
verify(initialisedFileSender).cancelOnError(exception);
}
@Test
void shouldCloseStream() {
try (var ioUtilsMock = mockStatic(IOUtils.class)) {
assertThrows(TechnicalException.class, TestWaitUntilFutureToComplete.this::waitUntilFutureToComplete);
ioUtilsMock.verify(() -> IOUtils.closeQuietly(inputStream));
}
}
}
@Nested
class TestOnException {
@SneakyThrows
@DisplayName("should cancel on timeout")
@ParameterizedTest(name = "when {0} is thrown")
@ValueSource(classes = { ExecutionException.class, TimeoutException.class })
void shouldCancelOnTimeoutOnTimeoutException(Class<Exception> exceptionClass) {
when(responseFuture.get(anyLong(), any())).thenThrow(exceptionClass);
assertThrows(TechnicalException.class, TestWaitUntilFutureToComplete.this::waitUntilFutureToComplete);
verify(initialisedFileSender).cancelOnTimeout();
}
@SneakyThrows
@DisplayName("should close stream")
@ParameterizedTest(name = "when {0} is thrown")
@ValueSource(classes = { ExecutionException.class, TimeoutException.class })
void shouldCloseStream(Class<Exception> exceptionClass) {
try (var ioUtilsMock = mockStatic(IOUtils.class)) {
when(responseFuture.get(anyLong(), any())).thenThrow(exceptionClass);
assertThrows(TechnicalException.class, TestWaitUntilFutureToComplete.this::waitUntilFutureToComplete);
ioUtilsMock.verify(() -> IOUtils.closeQuietly(inputStream));
}
}
}
private GrpcUploadBinaryFileResponse waitUntilFutureToComplete() {
return remoteService.waitUntilFutureToComplete(initialisedFileSender, inputStream);
}
}
}
\ No newline at end of file
/*
* Copyright (C) 2024 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.document.bescheid.binaryfile;
import com.thedeanda.lorem.LoremIpsum;
import de.ozgcloud.document.bescheid.BescheidResponseTestFactory;
import de.ozgcloud.document.bescheid.vorgang.VorgangTestFactory;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileMetaData;
public class GrpcUploadBinaryFileMetaDataTestFactory {
public static final String VORGANG_ID = VorgangTestFactory.ID_STR;
public static final String FIELD = LoremIpsum.getInstance().getWords(1);
public static final String CONTENT_TYPE = BescheidResponseTestFactory.CONTENT_TYPE;
public static final int SIZE = BescheidResponseTestFactory.BESCHEID_FILE_SIZE;
public static final String FILE_NAME = BescheidResponseTestFactory.BESCHEID_FILE_NAME;
public static GrpcUploadBinaryFileMetaData create() {
return createBuilder().build();
}
public static GrpcUploadBinaryFileMetaData.Builder createBuilder() {
return GrpcUploadBinaryFileMetaData.newBuilder()
.setVorgangId(VORGANG_ID)
.setField(FIELD)
.setContentType(CONTENT_TYPE)
.setSize(SIZE)
.setFileName(FILE_NAME);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment