Skip to content
Snippets Groups Projects
Commit 58a8df02 authored by OZGCloud's avatar OZGCloud
Browse files

Merge branch 'master' into OZG-7143-download-timeout

# Conflicts:
#	ozgcloud-common-lib/src/main/java/de/ozgcloud/common/binaryfile/GrpcBinaryFileServerDownloader.java
parents ea049edf 65647fb4
No related branches found
No related tags found
No related merge requests found
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
### 4.6.0 ### 4.6.0
* Update [OZGCloud License Generator](ozgcloud-common-license/readme.md) * Update [OZGCloud License Generator](ozgcloud-common-license/readme.md)
* `GrpcUtil` erweitern: mehr Schlüssel hinzufügen und Methoden, um diese Schlüssel aus gRPC-Metadaten zu extrahieren.
### 4.5.0 ### 4.5.0
* common-lib erweitern: gRPC Server Downloader für binäre Dateien hinzufügen * common-lib erweitern: gRPC Server Downloader für binäre Dateien hinzufügen
......
...@@ -25,7 +25,6 @@ package de.ozgcloud.common.binaryfile; ...@@ -25,7 +25,6 @@ package de.ozgcloud.common.binaryfile;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.common.errorhandling.TechnicalException;
import io.grpc.Context;
import io.grpc.stub.CallStreamObserver; import io.grpc.stub.CallStreamObserver;
import lombok.Builder; import lombok.Builder;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
...@@ -80,7 +79,7 @@ public class GrpcBinaryFileServerDownloader<T> { ...@@ -80,7 +79,7 @@ public class GrpcBinaryFileServerDownloader<T> {
void doStart() { void doStart() {
LOG.debug("Starting download."); LOG.debug("Starting download.");
handleSafety(this::setupStreams); handleSafety(this::setupStreams);
taskExecutor.execute(Context.current().wrap(this::startDownload)); taskExecutor.execute(this::startDownload);
callObserver.setOnReadyHandler(this::sendChunks); callObserver.setOnReadyHandler(this::sendChunks);
} }
......
...@@ -24,10 +24,10 @@ ...@@ -24,10 +24,10 @@
package de.ozgcloud.common.grpc; package de.ozgcloud.common.grpc;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import io.grpc.Metadata; import io.grpc.Metadata;
...@@ -39,8 +39,12 @@ import lombok.NoArgsConstructor; ...@@ -39,8 +39,12 @@ import lombok.NoArgsConstructor;
public class GrpcUtil { public class GrpcUtil {
public static final Key<byte[]> HEADER_KEY_USER_ID = createKeyOf("USER_ID-bin"); public static final Key<byte[]> HEADER_KEY_USER_ID = createKeyOf("USER_ID-bin");
public static final Key<byte[]> HEADER_KEY_USER_NAME = createKeyOf("USER_NAME-bin");
public static final Key<byte[]> HEADER_KEY_CLIENT_NAME = createKeyOf("CLIENT_NAME-bin"); public static final Key<byte[]> HEADER_KEY_CLIENT_NAME = createKeyOf("CLIENT_NAME-bin");
public static final Key<byte[]> HEADER_KEY_REQUEST_ID = createKeyOf("REQUEST_ID-bin"); public static final String KEY_REQUEST_ID = "REQUEST_ID-bin";
public static final Key<byte[]> HEADER_KEY_REQUEST_ID = createKeyOf(KEY_REQUEST_ID);
public static final Key<byte[]> HEADER_KEY_ACCESS_LIMITED_ORGAID = createKeyOf("ACCESS_LIMITED_TO_ORGANISATORISCHEEINHEITENID-bin");
public static final Key<byte[]> HEADER_KEY_ACCESS_LIMITED = createKeyOf("ACCESS_LIMITED-bin");
public static Key<String> keyOfString(String key) { public static Key<String> keyOfString(String key) {
return Key.of(key, Metadata.ASCII_STRING_MARSHALLER); return Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
...@@ -50,6 +54,30 @@ public class GrpcUtil { ...@@ -50,6 +54,30 @@ public class GrpcUtil {
return Key.of(key, Metadata.BINARY_BYTE_MARSHALLER); return Key.of(key, Metadata.BINARY_BYTE_MARSHALLER);
} }
public static Optional<String> getRequestId(Metadata headers) {
return getFromHeaders(HEADER_KEY_REQUEST_ID, headers);
}
public static Optional<String> getClientName(Metadata headers) {
return getFromHeaders(HEADER_KEY_CLIENT_NAME, headers);
}
public static Optional<String> getUserId(Metadata headers) {
return getFromHeaders(HEADER_KEY_USER_ID, headers);
}
public static Optional<String> getUserName(Metadata headers) {
return getFromHeaders(HEADER_KEY_USER_NAME, headers);
}
public static List<String> getAccessLimitedOrgaIds(Metadata headers) {
return getList(HEADER_KEY_ACCESS_LIMITED_ORGAID, headers);
}
public static Optional<Boolean> getAccessLimited(Metadata headers) {
return getFromHeaders(HEADER_KEY_ACCESS_LIMITED, headers).map(Boolean::parseBoolean);
}
public static Optional<String> getFromHeaders(String key, Metadata headers) { public static Optional<String> getFromHeaders(String key, Metadata headers) {
return getFromHeaders(createKeyOf(key), headers); return getFromHeaders(createKeyOf(key), headers);
} }
...@@ -58,14 +86,21 @@ public class GrpcUtil { ...@@ -58,14 +86,21 @@ public class GrpcUtil {
return Optional.ofNullable(headers.get(key)).map(GrpcUtil::byteToString); return Optional.ofNullable(headers.get(key)).map(GrpcUtil::byteToString);
} }
public static Collection<String> getCollection(String key, Metadata headers) { /**
final List<String> result = new ArrayList<>(); * @deprecated since 4.6.0, use {@link #getList(String, Metadata)} instead
var valuesOptional = Optional.ofNullable(headers.getAll(createKeyOf(key))); */
valuesOptional.ifPresent(valuesBytes -> result.addAll(StreamSupport.stream(valuesBytes.spliterator(), false) @Deprecated(since = "4.6.0", forRemoval = true)
.map(GrpcUtil::byteToString) public static List<String> getCollection(String key, Metadata headers) {
.toList())); return getList(key, headers);
}
public static List<String> getList(String key, Metadata headers) {
return getList(createKeyOf(key), headers);
}
return result; public static List<String> getList(Key<byte[]> key, Metadata headers) {
return Optional.ofNullable(headers.getAll(key)).map(valuesBytes -> StreamSupport.stream(valuesBytes.spliterator(), false))
.orElseGet(Stream::empty).map(GrpcUtil::byteToString).toList();
} }
private static String byteToString(byte[] bytes) { private static String byteToString(byte[] bytes) {
......
...@@ -121,13 +121,6 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -121,13 +121,6 @@ class GrpcBinaryFileServerDownloaderTest {
@Nested @Nested
class TestDoStart { class TestDoStart {
@Mock
private Context callContext;
@Mock
private Runnable wrappedRunnable;
@Captor
private ArgumentCaptor<Runnable> wrappedRunnableCaptor;
@Captor @Captor
private ArgumentCaptor<Runnable> runnableCaptor; private ArgumentCaptor<Runnable> runnableCaptor;
@Captor @Captor
...@@ -145,31 +138,15 @@ class GrpcBinaryFileServerDownloaderTest { ...@@ -145,31 +138,15 @@ class GrpcBinaryFileServerDownloaderTest {
verify(downloader).setupStreams(); verify(downloader).setupStreams();
} }
@Test
void shouldCallTaskExecutor() {
try (var contextMock = mockStatic(Context.class)) {
contextMock.when(Context::current).thenReturn(callContext);
when(callContext.wrap(any(Runnable.class))).thenReturn(wrappedRunnable);
downloader.doStart();
verify(taskExecutor).execute(wrappedRunnable);
}
}
@Test @Test
void shouldCallStartDownload() { void shouldCallStartDownload() {
try (var contextMock = mockStatic(Context.class)) { doNothing().when(downloader).startDownload();
contextMock.when(Context::current).thenReturn(callContext);
when(callContext.wrap(any(Runnable.class))).thenReturn(wrappedRunnable);
doNothing().when(downloader).startDownload();
downloader.doStart(); downloader.doStart();
verify(callContext).wrap(wrappedRunnableCaptor.capture()); verify(taskExecutor).execute(runnableCaptor.capture());
wrappedRunnableCaptor.getValue().run(); runnableCaptor.getValue().run();
verify(downloader).startDownload(); verify(downloader).startDownload();
}
} }
@SneakyThrows @SneakyThrows
......
...@@ -2,6 +2,7 @@ package de.ozgcloud.common.grpc; ...@@ -2,6 +2,7 @@ package de.ozgcloud.common.grpc;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import com.thedeanda.lorem.LoremIpsum;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
...@@ -9,98 +10,184 @@ import org.junit.jupiter.api.Test; ...@@ -9,98 +10,184 @@ import org.junit.jupiter.api.Test;
import io.grpc.Metadata; import io.grpc.Metadata;
import java.util.UUID;
class GrpcUtilTest { class GrpcUtilTest {
private static final String KEY_VALUE_BIN = "key_value-bin"; private static final String KEY_VALUE_BIN = "key_value-bin";
private static final String KEY_VALUE_STRING = "key_value"; private static final String KEY_VALUE_STRING = "key_value";
private static final String UNKNOWN_KEY_BIN = "unknown_key-bin"; private static final String UNKNOWN_KEY_BIN = "unknown_key-bin";
@DisplayName("Test Grpc Utility methods") private final Metadata header = new Metadata();
@DisplayName("Test creation of MetaData keys")
@Nested
class TestKeyGeneration {
@Test
void shouldCreateBinaryKey() {
var key = GrpcUtil.createKeyOf(KEY_VALUE_BIN);
assertThat(key.name()).isEqualTo(KEY_VALUE_BIN);
}
@Test
void shouldThrowExceptionBecauseOfMissingBinSuffix() {
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.createKeyOf("key"));
}
@Test
void shouldCreateAsciiKey() {
var key = GrpcUtil.keyOfString(KEY_VALUE_STRING);
assertThat(key.name()).isEqualTo(KEY_VALUE_STRING);
}
@Test
void shouldThrowExceptionBecauseOfBinSuffix() {
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.keyOfString(KEY_VALUE_BIN));
}
}
@DisplayName("Test reading values from the grpc header")
@Nested
class TestReadingFromHeader {
private static final String TEST_VALUE = LoremIpsum.getInstance().getWords(1);
@BeforeEach
void initMetadata() {
header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE.getBytes());
}
@Test
void shouldReadFromHeader() {
var value = GrpcUtil.getFromHeaders(KEY_VALUE_BIN, header);
assertThat(value).contains(TEST_VALUE);
}
@Test
void shouldReturnNullOnUnknownKey() {
var value = GrpcUtil.getFromHeaders(UNKNOWN_KEY_BIN, header);
assertThat(value).isEmpty();
}
}
@DisplayName("Test reading multiple values of a key from the grpc header")
@Nested
class TestReadingCollection {
private static final String TEST_VALUE_1 = LoremIpsum.getInstance().getWords(1);
private static final String TEST_VALUE_2 = LoremIpsum.getInstance().getWords(2);
@BeforeEach
void initMetadata() {
header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_1.getBytes());
header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_2.getBytes());
}
@Test
void shouldReadFromHeader() {
var values = GrpcUtil.getList(KEY_VALUE_BIN, header);
assertThat(values).hasSize(2).contains(TEST_VALUE_1, TEST_VALUE_2);
}
@Test
void shouldGetEmptyCollectionOnUnknownKey() {
var values = GrpcUtil.getList(UNKNOWN_KEY_BIN, header);
assertThat(values).isEmpty();
}
}
@Nested @Nested
class TestGrpcUtils { class TestGetRequestId {
@DisplayName("Test creation of MetaData keys") private static final String REQUEST_ID = UUID.randomUUID().toString();
@Nested
class TestKeyGeneration {
@Test @Test
void shouldCreateBinaryKey() { void shouldReturnRequestId() {
var key = GrpcUtil.createKeyOf(KEY_VALUE_BIN); header.put(GrpcUtil.HEADER_KEY_REQUEST_ID, REQUEST_ID.getBytes());
assertThat(key.name()).isEqualTo(KEY_VALUE_BIN); var result = GrpcUtil.getRequestId(header);
}
@Test assertThat(result).contains(REQUEST_ID);
void shouldThrowExceptionBecauseOfMissingBinSuffix() { }
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.createKeyOf("key")); }
}
@Nested
class TestGetClientName {
@Test private static final String CLIENT_NAME = LoremIpsum.getInstance().getWords(1);
void shouldCreateAsciiKey() {
var key = GrpcUtil.keyOfString(KEY_VALUE_STRING);
assertThat(key.name()).isEqualTo(KEY_VALUE_STRING); @Test
} void shouldReturnClientName() {
header.put(GrpcUtil.HEADER_KEY_CLIENT_NAME, CLIENT_NAME.getBytes());
@Test var result = GrpcUtil.getClientName(header);
void shouldThrowExceptionBecauseOfBinSuffix() {
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> GrpcUtil.keyOfString(KEY_VALUE_BIN)); assertThat(result).contains(CLIENT_NAME);
}
} }
}
@DisplayName("Test reading values from the grpc header") @Nested
@Nested class TestGetUserId {
class TestReadingFromHeader {
private static final String TEST_VALUE = "test-value";
private Metadata header = new Metadata(); private static final String USER_ID = LoremIpsum.getInstance().getWords(1);
@BeforeEach @Test
void initMetadata() { void shouldReturnUserId() {
header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE.getBytes()); header.put(GrpcUtil.HEADER_KEY_USER_ID, USER_ID.getBytes());
}
@Test var result = GrpcUtil.getUserId(header);
void shouldReadFromHeader() {
var value = GrpcUtil.getFromHeaders(KEY_VALUE_BIN, header);
assertThat(value).contains(TEST_VALUE); assertThat(result).contains(USER_ID);
} }
}
@Nested
class TestGetUserName {
@Test private static final String USER_NAME = LoremIpsum.getInstance().getWords(1);
void shouldReturnNullOnUnknownKey() {
var value = GrpcUtil.getFromHeaders(UNKNOWN_KEY_BIN, header);
assertThat(value).isEmpty(); @Test
} void shouldReturnUserName() {
header.put(GrpcUtil.HEADER_KEY_USER_NAME, USER_NAME.getBytes());
var result = GrpcUtil.getUserName(header);
assertThat(result).contains(USER_NAME);
} }
}
@DisplayName("Test reading multiple values of a key from the grpc header") @Nested
@Nested class TestGetAccessLimitedOrgaId {
class TestReadingCollection {
private static final String TEST_VALUE_1 = "test-value-1"; private static final String ACCESS_LIMITED_ORGAID = LoremIpsum.getInstance().getWords(1);
private static final String TEST_VALUE_2 = "test-value-2";
private Metadata header = new Metadata(); @Test
void shouldReturnAccessLimitedOrgaId() {
header.put(GrpcUtil.HEADER_KEY_ACCESS_LIMITED_ORGAID, ACCESS_LIMITED_ORGAID.getBytes());
@BeforeEach var result = GrpcUtil.getAccessLimitedOrgaIds(header);
void initMetadata() {
header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_1.getBytes()); assertThat(result).containsExactly(ACCESS_LIMITED_ORGAID);
header.put(GrpcUtil.createKeyOf(KEY_VALUE_BIN), TEST_VALUE_2.getBytes()); }
} }
@Nested
class TestGetAccessLimited {
@Test private static final boolean ACCESS_LIMITED = true;
void shouldReadFromHeader() {
var values = GrpcUtil.getCollection(KEY_VALUE_BIN, header);
assertThat(values).hasSize(2).contains(TEST_VALUE_1, TEST_VALUE_2); @Test
} void shouldReturnAccessLimited() {
header.put(GrpcUtil.HEADER_KEY_ACCESS_LIMITED, String.valueOf(ACCESS_LIMITED).getBytes());
@Test var result = GrpcUtil.getAccessLimited(header);
void shouldGetEmptyCollectionOnUnknownKey() {
var values = GrpcUtil.getCollection(UNKNOWN_KEY_BIN, header);
assertThat(values).isEmpty(); assertThat(result).contains(ACCESS_LIMITED);
}
} }
} }
} }
...@@ -393,7 +393,7 @@ ...@@ -393,7 +393,7 @@
<execution> <execution>
<id>attach-sources</id> <id>attach-sources</id>
<goals> <goals>
<goal>jar</goal> <goal>jar-no-fork</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment