From 7828b5a50eb4db328ed3fd245ae5c7a54ade1ad3 Mon Sep 17 00:00:00 2001 From: OZGCloud <ozgcloud@mgm-tp.com> Date: Thu, 21 Nov 2024 10:40:51 +0100 Subject: [PATCH] OZG-6990 implement comments from code review --- ozgcloud-common-lib/pom.xml | 5 ++ .../GrpcBinaryFileServerDownloader.java | 21 ++--- .../GrpcBinaryFileServerDownloaderTest.java | 77 ++++++++++--------- .../common/test/ReflectionTestUtils.java | 51 ++++++++++++ 4 files changed, 110 insertions(+), 44 deletions(-) create mode 100644 ozgcloud-common-test/src/main/java/de/ozgcloud/common/test/ReflectionTestUtils.java diff --git a/ozgcloud-common-lib/pom.xml b/ozgcloud-common-lib/pom.xml index f46dc0e..1373e1d 100644 --- a/ozgcloud-common-lib/pom.xml +++ b/ozgcloud-common-lib/pom.xml @@ -145,6 +145,11 @@ </dependency> <!-- test --> + <dependency> + <groupId>de.ozgcloud.common</groupId> + <artifactId>ozgcloud-common-test</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> diff --git a/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java b/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java index e19f14e..84c34d9 100644 --- a/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java +++ b/ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java @@ -53,7 +53,7 @@ public class GrpcBinaryFileServerDownloader<T> { private final byte[] buffer = new byte[GrpcBinaryFileServerDownloader.CHUNK_SIZE]; private final AtomicBoolean started = new AtomicBoolean(false); private final AtomicBoolean downloadFinished = new AtomicBoolean(false); - private final AtomicBoolean sendingFinished = new AtomicBoolean(false); + private final AtomicBoolean requestFinished = new AtomicBoolean(false); private PipedInputStream inputStream; private PipedOutputStream outputStream; @@ -108,15 +108,13 @@ public class GrpcBinaryFileServerDownloader<T> { } void doSendChunks() throws IOException { - if (sendingFinished.get()) { + if (requestFinished.get()) { return; } int bytesRead; while (callObserver.isReady()) { if ((bytesRead = inputStream.read(buffer)) == -1) { - if (downloadFinished.get()) { - completeDownload(); - } + tryCompleteRequest(); break; } callObserver.onNext(chunkBuilder.apply(ByteString.copyFrom(buffer, 0, bytesRead))); @@ -124,13 +122,18 @@ public class GrpcBinaryFileServerDownloader<T> { } } - void completeDownload() { - LOG.debug("try to complete download"); - if (sendingFinished.getAndSet(true)) { + void tryCompleteRequest() { + if (downloadFinished.get()) { + completeRequest(); + } + } + + void completeRequest() { + if (requestFinished.getAndSet(true)) { return; } + LOG.debug("Complete download request"); closeInputStream(); - LOG.debug("Complete request."); callObserver.onCompleted(); } diff --git a/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java b/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java index 9e42671..3da0664 100644 --- a/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java +++ b/ozgcloud-common-lib/src/test/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloaderTest.java @@ -25,6 +25,7 @@ package de.ozgcloud.common.binaryfile; import com.google.protobuf.ByteString; import de.ozgcloud.common.errorhandling.TechnicalException; +import de.ozgcloud.common.test.ReflectionTestUtils; import io.grpc.Context; import io.grpc.stub.CallStreamObserver; import lombok.SneakyThrows; @@ -271,11 +272,12 @@ class GrpcBinaryFileServerDownloaderTest { @SneakyThrows @BeforeEach void mock() { + doNothing().when(downloader).tryCompleteRequest(); when(callObserver.isReady()).thenReturn(true); when(inputStream.read(any())).thenReturn(readBytes, -1); setInputStreamField(inputStream); new Random().nextBytes(buffer); - setBufferArray(buffer); + ReflectionTestUtils.setField(downloader, "buffer", buffer); } @Test @@ -299,11 +301,11 @@ class GrpcBinaryFileServerDownloaderTest { @DisplayName("should call complete grpc stream if download has finished and stream has no data left") @Test void shouldCallCompleteDownload() { - setDownloadFinishedField(new AtomicBoolean(true)); + setDownloadFinishedField(true); doSendChunks(); - verify(downloader).completeDownload(); + verify(downloader).tryCompleteRequest(); } @SneakyThrows @@ -314,45 +316,65 @@ class GrpcBinaryFileServerDownloaderTest { } @Nested - class TestCompleteDownload { + class TestTryCompleteRequest { + + @Test + void shouldCallCompleteRequest() { + setDownloadFinishedField(true); + + downloader.tryCompleteRequest(); + + verify(downloader).completeRequest(); + } + + @Test + void shouldNotCallCompleteRequest() { + setDownloadFinishedField(false); + + downloader.tryCompleteRequest(); + + verify(downloader, never()).completeRequest(); + } + } + + @Nested + class TestCompleteRequest { @Mock private PipedInputStream inputStream; @BeforeEach void mock() { - setSendingFinishedField(new AtomicBoolean(false)); - setDownloadFinishedField(new AtomicBoolean(true)); + setSendingFinishedField(false); + setDownloadFinishedField(true); setInputStreamField(inputStream); } @Test void shouldSetSendingFinished() { - downloader.completeDownload(); + downloader.completeRequest(); - assertThat(getSendingFinished()).isTrue(); + assertThat(getRequestFinished()).isTrue(); } @SneakyThrows @Test void shouldCallCloseInputStream() { - downloader.completeDownload(); + downloader.completeRequest(); verify(downloader).closeInputStream(); } @Test void shouldCallOnCompleted() { - downloader.completeDownload(); + downloader.completeRequest(); verify(callObserver).onCompleted(); } @SneakyThrows - private boolean getSendingFinished() { - var sendingFinishedField = downloader.getClass().getDeclaredField("sendingFinished"); - sendingFinishedField.setAccessible(true); - return ((AtomicBoolean) sendingFinishedField.get(downloader)).get(); + private boolean getRequestFinished() { + return ReflectionTestUtils.getField(downloader, "requestFinished", AtomicBoolean.class).get(); } } @@ -421,37 +443,22 @@ class GrpcBinaryFileServerDownloaderTest { @SneakyThrows private void setOutputStreamField(OutputStream outputStream) { - var outputStreamField = downloader.getClass().getDeclaredField("outputStream"); - outputStreamField.setAccessible(true); - outputStreamField.set(downloader, outputStream); + ReflectionTestUtils.setField(downloader, "outputStream", outputStream); } @SneakyThrows private void setInputStreamField(InputStream inputStream) { - var inputStreamField = downloader.getClass().getDeclaredField("inputStream"); - inputStreamField.setAccessible(true); - inputStreamField.set(downloader, inputStream); - } - - @SneakyThrows - private void setDownloadFinishedField(AtomicBoolean downloadInProgress) { - var downloadInProgressField = downloader.getClass().getDeclaredField("downloadFinished"); - downloadInProgressField.setAccessible(true); - downloadInProgressField.set(downloader, downloadInProgress); + ReflectionTestUtils.setField(downloader, "inputStream", inputStream); } @SneakyThrows - private void setSendingFinishedField(AtomicBoolean downloadInProgress) { - var downloadInProgressField = downloader.getClass().getDeclaredField("sendingFinished"); - downloadInProgressField.setAccessible(true); - downloadInProgressField.set(downloader, downloadInProgress); + private void setDownloadFinishedField(boolean downloadFinished) { + ReflectionTestUtils.setField(downloader, "downloadFinished", new AtomicBoolean(downloadFinished)); } @SneakyThrows - private void setBufferArray(byte[] buffer) { - var downloadInProgressField = downloader.getClass().getDeclaredField("buffer"); - downloadInProgressField.setAccessible(true); - downloadInProgressField.set(downloader, buffer); + private void setSendingFinishedField(boolean requestFinished) { + ReflectionTestUtils.setField(downloader, "requestFinished", new AtomicBoolean(requestFinished)); } static class GrpcResponseDummy { diff --git a/ozgcloud-common-test/src/main/java/de/ozgcloud/common/test/ReflectionTestUtils.java b/ozgcloud-common-test/src/main/java/de/ozgcloud/common/test/ReflectionTestUtils.java new file mode 100644 index 0000000..d5cc01a --- /dev/null +++ b/ozgcloud-common-test/src/main/java/de/ozgcloud/common/test/ReflectionTestUtils.java @@ -0,0 +1,51 @@ +/* + * 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.common.test; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; + +import java.lang.reflect.Field; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ReflectionTestUtils { + + @SneakyThrows + public static <T> T getField(Object target, String fieldName, Class<T> fieldType) { + return fieldType.cast(getDeclaredField(target, fieldName).get(target)); + } + + @SneakyThrows + public static void setField(Object target, String fieldName, Object value) { + getDeclaredField(target, fieldName).set(target, value); // NOSONAR + } + + @SneakyThrows + private static Field getDeclaredField(Object target, String fieldName) { + var field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); // NOSONAR + return field; + } +} -- GitLab