Skip to content
Snippets Groups Projects
Commit f7fe32ba authored by Krzysztof Witukiewicz's avatar Krzysztof Witukiewicz
Browse files

Merge branch 'OZG-7262-downloader-error-handling' into 'main'

OZG-7262 OZG-7566 Notify callObserver about error

See merge request !6
parents cfca76e5 884dcc0b
No related branches found
No related tags found
1 merge request!6OZG-7262 OZG-7566 Notify callObserver about error
...@@ -23,22 +23,26 @@ ...@@ -23,22 +23,26 @@
*/ */
package de.ozgcloud.common.binaryfile; package de.ozgcloud.common.binaryfile;
import com.google.protobuf.ByteString;
import de.ozgcloud.common.errorhandling.TechnicalException;
import io.grpc.stub.CallStreamObserver;
import lombok.Builder;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.IOUtils;
import org.springframework.core.task.TaskExecutor;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.apache.commons.io.IOUtils;
import org.springframework.core.task.TaskExecutor;
import com.google.protobuf.ByteString;
import de.ozgcloud.common.errorhandling.TechnicalException;
import io.grpc.stub.CallStreamObserver;
import lombok.Builder;
import lombok.extern.log4j.Log4j2;
@Log4j2 @Log4j2
public class GrpcBinaryFileServerDownloader<T> { public class GrpcBinaryFileServerDownloader<T> {
...@@ -49,10 +53,11 @@ public class GrpcBinaryFileServerDownloader<T> { ...@@ -49,10 +53,11 @@ public class GrpcBinaryFileServerDownloader<T> {
private final Consumer<OutputStream> downloadConsumer; private final Consumer<OutputStream> downloadConsumer;
private final TaskExecutor taskExecutor; private final TaskExecutor taskExecutor;
private final byte[] buffer = new byte[GrpcBinaryFileServerDownloader.CHUNK_SIZE]; private final byte[] buffer = new byte[CHUNK_SIZE];
private final AtomicBoolean started = new AtomicBoolean(false); private final AtomicBoolean started = new AtomicBoolean(false);
private final AtomicBoolean downloadFinished = new AtomicBoolean(false); private final AtomicBoolean downloadFinished = new AtomicBoolean(false);
private final AtomicBoolean requestFinished = new AtomicBoolean(false); private final AtomicBoolean requestFinished = new AtomicBoolean(false);
private final AtomicReference<TechnicalException> downloadError = new AtomicReference<>();
private PipedInputStream inputStream; private PipedInputStream inputStream;
private PipedOutputStream outputStream; private PipedOutputStream outputStream;
...@@ -78,19 +83,36 @@ public class GrpcBinaryFileServerDownloader<T> { ...@@ -78,19 +83,36 @@ public class GrpcBinaryFileServerDownloader<T> {
void doStart() { void doStart() {
LOG.debug("Starting download."); LOG.debug("Starting download.");
handleSafety(this::setupStreams); safelySetupStreams();
taskExecutor.execute(this::startDownload); taskExecutor.execute(this::startDownload);
callObserver.setOnReadyHandler(this::sendChunks); callObserver.setOnReadyHandler(this::sendChunks);
} }
void safelySetupStreams() {
try {
setupStreams();
} catch (Exception e) {
closeOutputStream();
closeInputStream();
throw new TechnicalException("Error while setting up streams", e);
}
}
void setupStreams() throws IOException { void setupStreams() throws IOException {
outputStream = new PipedOutputStream(); outputStream = new PipedOutputStream();
inputStream = new PipedInputStream(GrpcBinaryFileServerDownloader.CHUNK_SIZE); inputStream = new PipedInputStream(CHUNK_SIZE);
outputStream.connect(inputStream); outputStream.connect(inputStream);
} }
void startDownload() { void startDownload() {
handleSafety(this::doDownload); try {
doDownload();
sendChunks();
} catch (Exception e) {
downloadError.set(new TechnicalException("Error while downloading file contents", e));
} finally {
closeOutputStream();
}
} }
void doDownload() { void doDownload() {
...@@ -98,12 +120,14 @@ public class GrpcBinaryFileServerDownloader<T> { ...@@ -98,12 +120,14 @@ public class GrpcBinaryFileServerDownloader<T> {
downloadConsumer.accept(outputStream); downloadConsumer.accept(outputStream);
LOG.debug("Download completed."); LOG.debug("Download completed.");
downloadFinished.set(true); downloadFinished.set(true);
closeOutputStream();
sendChunks();
} }
synchronized void sendChunks() { synchronized void sendChunks() {
handleSafety(this::doSendChunks); try {
doSendChunks();
} catch (Exception e) {
completeRequestWithError(new TechnicalException("Error while sending chunks", e));
}
} }
void doSendChunks() throws IOException { void doSendChunks() throws IOException {
...@@ -111,7 +135,7 @@ public class GrpcBinaryFileServerDownloader<T> { ...@@ -111,7 +135,7 @@ public class GrpcBinaryFileServerDownloader<T> {
return; return;
} }
int bytesRead; int bytesRead;
while (callObserver.isReady()) { while (isReady()) {
if ((bytesRead = inputStream.read(buffer)) == -1) { if ((bytesRead = inputStream.read(buffer)) == -1) {
tryCompleteRequest(); tryCompleteRequest();
break; break;
...@@ -121,30 +145,33 @@ public class GrpcBinaryFileServerDownloader<T> { ...@@ -121,30 +145,33 @@ public class GrpcBinaryFileServerDownloader<T> {
} }
} }
private boolean isReady() {
return callObserver.isReady();
}
void tryCompleteRequest() { void tryCompleteRequest() {
if (shouldCompleteRequest()) { if (Objects.nonNull(downloadError.get())) {
completeRequest(); throw downloadError.get();
} else if (downloadFinished.get()) {
completeRequestNormally();
} }
} }
boolean shouldCompleteRequest() { void completeRequestWithError(TechnicalException e) {
return downloadFinished.get() && requestFinished.compareAndSet(false, true); LOG.debug("Complete download request with error");
finishRequest();
throw e;
} }
void completeRequest() { void completeRequestNormally() {
LOG.debug("Complete download request"); LOG.debug("Complete download request");
closeInputStream(); finishRequest();
callObserver.onCompleted(); callObserver.onCompleted();
} }
void handleSafety(ExceptionalRunnable runnable) { private void finishRequest() {
try { requestFinished.set(true);
runnable.run();
} catch (Exception e) {
closeOutputStream();
closeInputStream(); closeInputStream();
throw new TechnicalException("Error occurred during downloading file content download.", e);
}
} }
void closeOutputStream() { void closeOutputStream() {
...@@ -154,5 +181,4 @@ public class GrpcBinaryFileServerDownloader<T> { ...@@ -154,5 +181,4 @@ public class GrpcBinaryFileServerDownloader<T> {
void closeInputStream() { void closeInputStream() {
IOUtils.closeQuietly(inputStream, e -> LOG.error("InputStream cannot be closed.", e)); IOUtils.closeQuietly(inputStream, e -> LOG.error("InputStream cannot be closed.", e));
} }
} }
\ No newline at end of file
...@@ -23,20 +23,9 @@ ...@@ -23,20 +23,9 @@
*/ */
package de.ozgcloud.common.binaryfile; package de.ozgcloud.common.binaryfile;
import com.google.protobuf.ByteString; import static org.assertj.core.api.Assertions.*;
import de.ozgcloud.common.errorhandling.TechnicalException; import static org.mockito.ArgumentMatchers.*;
import de.ozgcloud.common.test.ReflectionTestUtils; import static org.mockito.Mockito.*;
import io.grpc.Context;
import io.grpc.stub.CallStreamObserver;
import lombok.SneakyThrows;
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.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.springframework.core.task.TaskExecutor;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
...@@ -45,12 +34,25 @@ import java.io.PipedInputStream; ...@@ -45,12 +34,25 @@ import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.util.Random; import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.BeforeEach;
import static org.mockito.ArgumentMatchers.*; import org.junit.jupiter.api.DisplayName;
import static org.mockito.Mockito.*; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.springframework.core.task.TaskExecutor;
import com.google.protobuf.ByteString;
import de.ozgcloud.common.errorhandling.TechnicalException;
import de.ozgcloud.common.test.ReflectionTestUtils;
import io.grpc.stub.CallStreamObserver;
import lombok.SneakyThrows;
class GrpcBinaryFileServerDownloaderTest { class GrpcBinaryFileServerDownloaderTest {
...@@ -71,7 +73,6 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -71,7 +73,6 @@ class GrpcBinaryFileServerDownloaderTest {
.chunkBuilder(chunkBuilder).taskExecutor(taskExecutor).build()); .chunkBuilder(chunkBuilder).taskExecutor(taskExecutor).build());
} }
@DisplayName("Start")
@Nested @Nested
class TestStart { class TestStart {
...@@ -117,25 +118,23 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -117,25 +118,23 @@ class GrpcBinaryFileServerDownloaderTest {
} }
} }
@DisplayName("do start")
@Nested @Nested
class TestDoStart { class TestDoStart {
@Captor @Captor
private ArgumentCaptor<Runnable> runnableCaptor; private ArgumentCaptor<Runnable> runnableCaptor;
@Captor
private ArgumentCaptor<ExceptionalRunnable> setupStreamCaptor; @BeforeEach
void init() {
doNothing().when(downloader).safelySetupStreams();
}
@SneakyThrows @SneakyThrows
@Test @Test
void shouldCallSetupStreams() { void shouldSafelySetupStreams() {
doNothing().when(downloader).handleSafety(any());
downloader.doStart(); downloader.doStart();
verify(downloader).handleSafety(setupStreamCaptor.capture()); verify(downloader).safelySetupStreams();
setupStreamCaptor.getValue().run();
verify(downloader).setupStreams();
} }
@Test @Test
...@@ -159,28 +158,138 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -159,28 +158,138 @@ class GrpcBinaryFileServerDownloaderTest {
} }
} }
@DisplayName("Start download")
@Nested @Nested
class TestStartDownload { class TestSafelySetupStreams {
@Captor @SneakyThrows
private ArgumentCaptor<ExceptionalRunnable> runnableCaptor; @Test
void shouldSetupStreams() {
doNothing().when(downloader).setupStreams();
safelySetupStreams();
verify(downloader).setupStreams();
}
@Nested
class OnException {
@Mock
private PipedOutputStream outputStream;
@Mock
private PipedInputStream inputStream;
private final IOException exception = new IOException();
@SneakyThrows
@BeforeEach
void init() {
setInputStreamField(inputStream);
setOutputStreamField(outputStream);
doThrow(exception).when(downloader).setupStreams();
}
@Test
void shouldThrowBinaryFileDownloadException() {
assertThatThrownBy(() -> downloader.safelySetupStreams()).isInstanceOf(TechnicalException.class).hasCause(exception);
}
@SneakyThrows
@Test
void shouldCloseOutputStream() {
catchThrowable(TestSafelySetupStreams.this::safelySetupStreams);
verify(outputStream).close();
}
@SneakyThrows @SneakyThrows
@Test @Test
void shouldCallDoDownload() { void shouldCloseInputStream() {
doNothing().when(downloader).handleSafety(any()); catchThrowable(TestSafelySetupStreams.this::safelySetupStreams);
verify(inputStream).close();
}
}
private void safelySetupStreams() {
downloader.safelySetupStreams();
}
}
@Nested
class TestStartDownload {
@Mock
private PipedOutputStream outputStream;
@BeforeEach
void init() {
setOutputStreamField(outputStream);
}
@Test
void shouldErrorBeInitiallyNull() {
assertThat(getDownloadError()).isNull();
}
@Nested
class OnNoException {
@BeforeEach
void init() {
doNothing().when(downloader).doDownload(); doNothing().when(downloader).doDownload();
}
@Test
void shouldDoDownload() {
downloader.startDownload(); downloader.startDownload();
verify(downloader).handleSafety(runnableCaptor.capture());
runnableCaptor.getValue().run();
verify(downloader).doDownload(); verify(downloader).doDownload();
} }
@SneakyThrows
@Test
void shouldCloseOutputStream() {
downloader.startDownload();
verify(outputStream).close();
}
@Test
void shouldSendChunks() {
downloader.startDownload();
verify(downloader).sendChunks();
}
}
@Nested
class OnException {
private final TechnicalException exception = new TechnicalException("error");
@BeforeEach
void init() {
doThrow(exception).when(downloader).doDownload();
}
@Test
void shouldSetError() {
downloader.startDownload();
assertThat(getDownloadError()).isInstanceOf(TechnicalException.class).hasCause(exception);
}
@SneakyThrows
@Test
void shouldCloseOutputStream() {
downloader.startDownload();
verify(outputStream).close();
}
}
} }
@DisplayName("do")
@Nested @Nested
class TestDoDownload { class TestDoDownload {
...@@ -192,7 +301,6 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -192,7 +301,6 @@ class GrpcBinaryFileServerDownloaderTest {
setOutputStreamField(outputStream); setOutputStreamField(outputStream);
} }
@SneakyThrows
@Test @Test
void shouldCallDownloadConsumer() { void shouldCallDownloadConsumer() {
downloader.doDownload(); downloader.doDownload();
...@@ -200,43 +308,106 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -200,43 +308,106 @@ class GrpcBinaryFileServerDownloaderTest {
verify(downloadConsumer).accept(outputStream); verify(downloadConsumer).accept(outputStream);
} }
@SneakyThrows
@Test @Test
void shouldCloseOutputStream() { void shouldDownloadFinishedBeInitiallyFalse() {
assertThat(getDownloadFinished()).isFalse();
}
@Test
void shouldSetDownloadFinished() {
downloader.doDownload(); downloader.doDownload();
verify(outputStream).close(); assertThat(getDownloadFinished()).isTrue();
} }
} }
@DisplayName("Send chunks")
@Nested @Nested
class TestSendChunks { class TestSendChunks {
@Nested
class OnNoException {
@SneakyThrows @SneakyThrows
@Test @BeforeEach
void shouldCallHandleSafety() { void init() {
doNothing().when(downloader).doSendChunks(); doNothing().when(downloader).doSendChunks();
}
@SneakyThrows
@Test
void shouldDoSendChunks() {
downloader.sendChunks(); downloader.sendChunks();
verify(downloader).handleSafety(any(ExceptionalRunnable.class)); verify(downloader).doSendChunks();
}
} }
@Nested
class OnException {
private final IOException exception = new IOException();
@Captor
private ArgumentCaptor<TechnicalException> argumentCaptor;
@SneakyThrows @SneakyThrows
@Test @BeforeEach
void shouldCallDoDownload() { void init() {
doNothing().when(downloader).doSendChunks(); doThrow(exception).when(downloader).doSendChunks();
doNothing().when(downloader).completeRequestWithError(any());
}
@Test
void shouldCompleteRequestWithError() {
downloader.sendChunks(); downloader.sendChunks();
verify(downloader).doSendChunks(); verify(downloader).completeRequestWithError(argumentCaptor.capture());
assertThat(argumentCaptor.getValue()).isInstanceOf(TechnicalException.class).hasCause(exception);
}
}
} }
@DisplayName("do")
@Nested @Nested
class TestDoSendChunks { class TestDoSendChunks {
@Nested
class OnRequestFinished {
@BeforeEach
void init() {
setRequestFinishedField(true);
}
@Test
void shouldNotInteractWithCallObserver() {
doSendChunks();
verifyNoInteractions(callObserver);
}
}
@Nested
class OnRequestNotFinished {
@Nested
class OnNotReady {
@BeforeEach
void init() {
when(callObserver.isReady()).thenReturn(false);
}
@Test
void shouldOnlyCallIsReadyOnObserver() {
doSendChunks();
verify(callObserver).isReady();
verifyNoMoreInteractions(callObserver);
}
}
@Nested
class OnReady {
@Mock @Mock
private PipedInputStream inputStream; private PipedInputStream inputStream;
@Captor @Captor
...@@ -277,87 +448,67 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -277,87 +448,67 @@ class GrpcBinaryFileServerDownloaderTest {
@DisplayName("should call complete grpc stream if download has finished and stream has no data left") @DisplayName("should call complete grpc stream if download has finished and stream has no data left")
@Test @Test
void shouldCallCompleteDownload() { void shouldTryCompleteRequest() {
setDownloadFinishedField(true); setDownloadFinishedField(true);
doSendChunks(); doSendChunks();
verify(downloader).tryCompleteRequest(); verify(downloader).tryCompleteRequest();
} }
}
}
@SneakyThrows @SneakyThrows
private void doSendChunks() { private void doSendChunks() {
downloader.doSendChunks(); downloader.doSendChunks();
} }
} }
}
@Nested @Nested
class TestTryCompleteRequest { class TestTryCompleteRequest {
@Test @Nested
void shouldCallShouldCompleteRequest() { class OnError {
downloader.tryCompleteRequest();
verify(downloader).shouldCompleteRequest();
}
@Test private final TechnicalException exception = new TechnicalException("error");
void shouldCallCompleteRequest() {
doReturn(true).when(downloader).shouldCompleteRequest();
downloader.tryCompleteRequest(); @BeforeEach
void init() {
verify(downloader).completeRequest(); setDownloadErrorField(exception);
} }
@Test @Test
void shouldNotCallCompleteRequest() { void shouldThrowException() {
doReturn(false).when(downloader).shouldCompleteRequest(); assertThatThrownBy(downloader::tryCompleteRequest).isSameAs(exception);
downloader.tryCompleteRequest();
verify(downloader, never()).completeRequest();
} }
} }
@Nested @Nested
class TestShouldCompleteRequest { class OnDownloadFinished {
@Nested
class TestWhenDownloadFinished {
@BeforeEach @BeforeEach
void init() { void init() {
setDownloadFinishedField(true); setDownloadFinishedField(true);
doNothing().when(downloader).completeRequestNormally();
} }
@Test @Test
void shouldReturnTrue() { void shouldNotCompleteRequestWithError() {
var result = downloader.shouldCompleteRequest(); downloader.tryCompleteRequest();
assertThat(result).isTrue();
}
@Test
void shouldReturnFalseIfRequestFinished() {
setRequestFinishedField(true);
var result = downloader.shouldCompleteRequest();
assertThat(result).isFalse(); verify(downloader, never()).completeRequestWithError(any());
} }
@Test @Test
void shouldUpdateRequestFinished() { void shouldCompleteRequestNormally() {
downloader.shouldCompleteRequest(); downloader.tryCompleteRequest();
assertThat(getRequestFinished()).isTrue(); verify(downloader).completeRequestNormally();
} }
} }
@Nested @Nested
class TestWhenDownloadRunning { class OnDownloadNotFinished {
@BeforeEach @BeforeEach
void init() { void init() {
...@@ -365,118 +516,85 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -365,118 +516,85 @@ class GrpcBinaryFileServerDownloaderTest {
} }
@Test @Test
void shouldReturnFalse() { void shouldNotCompleteRequestNormally() {
var result = downloader.shouldCompleteRequest(); downloader.tryCompleteRequest();
assertThat(result).isFalse(); verify(downloader, never()).completeRequestNormally();
} }
@Test @Test
void shouldNotUpdateRequestFinished() { void shouldNotCompleteRequestWithError() {
downloader.shouldCompleteRequest(); downloader.tryCompleteRequest();
assertThat(getRequestFinished()).isFalse(); verify(downloader, never()).completeRequestWithError(any());
} }
} }
} }
@Nested @Nested
class TestCompleteRequest { class TestCompleteRequestNormally {
@Mock
private PipedInputStream inputStream;
@BeforeEach @BeforeEach
void mock() { void init() {
setRequestFinishedField(false); doNothing().when(downloader).closeInputStream();
setDownloadFinishedField(true);
setInputStreamField(inputStream);
} }
@SneakyThrows
@Test @Test
void shouldCallCloseInputStream() { void shouldSetRequestFinished() {
downloader.completeRequest(); assertThat(getRequestFinished()).isFalse();
verify(downloader).closeInputStream(); downloader.completeRequestNormally();
assertThat(getRequestFinished()).isTrue();
} }
@Test @Test
void shouldCallOnCompleted() { void shouldCloseInputStream() {
downloader.completeRequest(); downloader.completeRequestNormally();
verify(callObserver).onCompleted(); verify(downloader).closeInputStream();
} }
@SneakyThrows @Test
private boolean getRequestFinished() { void shouldNotifyObserver() {
return ReflectionTestUtils.getField(downloader, "requestFinished", AtomicBoolean.class).get(); downloader.completeRequestNormally();
verify(callObserver).onCompleted();
} }
} }
@DisplayName("Handle safety")
@Nested
class TestHandleSafety {
@DisplayName("on exception")
@Nested @Nested
class TestOnException { class TestCompleteRequestWithError {
@Mock private final TechnicalException error = new TechnicalException("error");
private PipedOutputStream outputStream;
@Mock
private PipedInputStream inputStream;
private final IOException exception = new IOException();
@SneakyThrows
@BeforeEach @BeforeEach
void mock() { void init() {
setInputStreamField(inputStream); doNothing().when(downloader).closeInputStream();
setOutputStreamField(outputStream);
} }
@SneakyThrows
@Test @Test
void shouldThrowTechnicalException() { void shouldSetRequestFinished() {
assertThatThrownBy(this::handleSafety).isInstanceOf(TechnicalException.class).extracting(Throwable::getCause).isEqualTo(exception); assertThat(getRequestFinished()).isFalse();
}
@SneakyThrows catchException(() -> downloader.completeRequestWithError(error));
@Test
void shouldCloseOutputStream() {
try {
handleSafety();
} catch (Exception e) {
// do nothing
}
verify(outputStream).close(); assertThat(getRequestFinished()).isTrue();
} }
@SneakyThrows
@Test @Test
void shouldCloseInputStream() { void shouldCloseInputStream() {
try { catchException(() -> downloader.completeRequestWithError(error));
handleSafety();
} catch (Exception e) {
// do nothing
}
verify(inputStream).close();
}
private void handleSafety() { verify(downloader).closeInputStream();
downloader.handleSafety(this::dummyMethodThrowingException);
} }
private void dummyMethodThrowingException() throws IOException { @Test
throw exception; void shouldThrowException() {
assertThatThrownBy(() -> downloader.completeRequestWithError(error)).isSameAs(error);
} }
} }
}
private void setOutputStreamField(OutputStream outputStream) { private void setOutputStreamField(OutputStream outputStream) {
ReflectionTestUtils.setField(downloader, "outputStream", outputStream); ReflectionTestUtils.setField(downloader, "outputStream", outputStream);
} }
...@@ -485,10 +603,6 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -485,10 +603,6 @@ class GrpcBinaryFileServerDownloaderTest {
ReflectionTestUtils.setField(downloader, "inputStream", inputStream); ReflectionTestUtils.setField(downloader, "inputStream", inputStream);
} }
private void setDownloadFinishedField(boolean downloadFinished) {
ReflectionTestUtils.setField(downloader, "downloadFinished", new AtomicBoolean(downloadFinished));
}
private void setRequestFinishedField(boolean requestFinished) { private void setRequestFinishedField(boolean requestFinished) {
ReflectionTestUtils.setField(downloader, "requestFinished", new AtomicBoolean(requestFinished)); ReflectionTestUtils.setField(downloader, "requestFinished", new AtomicBoolean(requestFinished));
} }
...@@ -497,6 +611,22 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -497,6 +611,22 @@ class GrpcBinaryFileServerDownloaderTest {
return ReflectionTestUtils.getField(downloader, "requestFinished", AtomicBoolean.class).get(); return ReflectionTestUtils.getField(downloader, "requestFinished", AtomicBoolean.class).get();
} }
static class GrpcResponseDummy { private void setDownloadErrorField(TechnicalException error) {
ReflectionTestUtils.setField(downloader, "downloadError", new AtomicReference<>(error));
}
private TechnicalException getDownloadError() {
return (TechnicalException) ReflectionTestUtils.getField(downloader, "downloadError", AtomicReference.class).get();
}
private void setDownloadFinishedField(boolean downloadFinished) {
ReflectionTestUtils.setField(downloader, "downloadFinished", new AtomicBoolean(downloadFinished));
}
private boolean getDownloadFinished() {
return ReflectionTestUtils.getField(downloader, "downloadFinished", AtomicBoolean.class).get();
}
private static class GrpcResponseDummy {
} }
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment