Skip to content
Snippets Groups Projects
Commit 8a84e490 authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-2626_grpc_security' (#9) from OZG-2626_grpc_security into master

parents e42f3bd9 e9a8110d
No related branches found
No related tags found
No related merge requests found
Showing
with 753 additions and 19 deletions
......@@ -95,7 +95,7 @@ pipeline {
container("quarkus-22"){
withCredentials([usernamePassword(credentialsId: 'jenkins-docker-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
sh './mvnw -pl user-manager-server -s $MAVEN_SETTINGS clean package -DskipTests -Pnative -Dquarkus.container-image.registry=docker.ozg-sh.de -Dquarkus.container-image.username=${USER} -Dquarkus.container-image.password=${PASSWORD} -Dquarkus.container-image.push=true -Dquarkus.container-image.build=true -Dmaven.wagon.http.retryHandler.count=3'
sh './mvnw -pl user-manager-server -s $MAVEN_SETTINGS clean verify -Pnative -Dquarkus.container-image.registry=docker.ozg-sh.de -Dquarkus.container-image.username=${USER} -Dquarkus.container-image.password=${PASSWORD} -Dquarkus.container-image.push=true -Dquarkus.container-image.build=true -Dmaven.wagon.http.retryHandler.count=3'
}
}
}
......
......@@ -141,10 +141,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-json</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>log4j-jboss-logmanager</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>log4j2-jboss-logmanager</artifactId>
......
package de.itvsh.kop.user.common.callcontext;
import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;
import java.util.Optional;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
@Builder
@Getter
public class CallContextUser implements Serializable, Principal {
private static final long serialVersionUID = 1L;
private final String clientName;
@Builder.Default
private final transient Optional<String> userId = Optional.empty();
@Builder.Default
private final transient Optional<String> userName = Optional.empty();
@Singular
private final Collection<String> organisatorischeEinheitenIds;
@Builder.Default
private final transient boolean organisationEinheitenIdCheckNecessary = false;
@Builder.Default
private final transient boolean authenticated = false;
@Override
public String getName() {
return clientName;
}
}
package de.itvsh.kop.user.common.callcontext;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
@RequestScoped
public class CurrentCallContextUserService {
private CallContextUser user;
void setCallContextUser(CallContextUser callContextUser) {
this.user = callContextUser;
}
public Optional<CallContextUser> getCurrentCallContextUser() {
return Optional.ofNullable(user);
}
}
package de.itvsh.kop.user.common.callcontext;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import org.apache.logging.log4j.CloseableThreadContext;
import io.grpc.ForwardingServerCallListener;
import io.grpc.Metadata;
import io.grpc.Metadata.Key;
import io.grpc.ServerCall;
import io.grpc.ServerCall.Listener;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.quarkus.grpc.GlobalInterceptor;
import lombok.extern.log4j.Log4j2;
@ApplicationScoped
@GlobalInterceptor
@Log4j2
public class GrpcCallContextInterceptor implements ServerInterceptor {
private static final String REQUEST_ID_KEY = "requestId";
static final String KEY_USER_ID = "USER_ID-bin";
static final String KEY_USER_NAME = "USER_NAME-bin";
static final String KEY_CLIENT_NAME = "CLIENT_NAME-bin";
static final String KEY_REQUEST_ID = "REQUEST_ID-bin";
static final String KEY_ACCESS_LIMITED_ORGAID = "ACCESS_LIMITED_TO_ORGANISATORISCHEEINHEITENID-bin";
static final String KEY_ACCESS_LIMITED = "ACCESS_LIMITED-bin";
static final String REQUEST_ID_PLACEHOLDER = "no-requestId-given";
@Inject
CurrentCallContextUserService userService;
@Override
public <Q, S> Listener<Q> interceptCall(ServerCall<Q, S> call, Metadata headers, ServerCallHandler<Q, S> next) {
return new LogContextSettingListener<>(next.startCall(call, headers), headers);
}
class LogContextSettingListener<A> extends ForwardingServerCallListener.SimpleForwardingServerCallListener<A> {
private final String requestId;
private final Metadata headers;
public LogContextSettingListener(ServerCall.Listener<A> delegate, Metadata headers) {
super(delegate);
this.headers = headers;
this.requestId = getRequestId();
}
@Override
public void onMessage(A message) {
doSurroundOn(() -> super.onMessage(message));
}
@Override
public void onHalfClose() {
doSurroundOn(super::onHalfClose);
}
@Override
public void onCancel() {
doSurroundOn(super::onCancel);
}
@Override
public void onComplete() {
doSurroundOn(super::onComplete);
}
@Override
public void onReady() {
doSurroundOn(super::onReady);
}
void doSurroundOn(Runnable runnable) {
try (CloseableThreadContext.Instance ctc = CloseableThreadContext.put(REQUEST_ID_KEY, requestId)) {
startSecurityContext();
runnable.run();
}
}
String getRequestId() {
return getFromHeaders(KEY_REQUEST_ID, headers).orElseGet(() -> UUID.randomUUID().toString());
}
void startSecurityContext() {
userService.setCallContextUser(createCallContextUser());
}
CallContextUser createCallContextUser() {
var builder = CallContextUser.builder()
.userId(getFromHeaders(GrpcCallContextInterceptor.KEY_USER_ID, headers))
.userName(getFromHeaders(KEY_USER_NAME, headers))
.authenticated(true)
.organisatorischeEinheitenIds(getCollection(KEY_ACCESS_LIMITED_ORGAID, headers));
getFromHeaders(KEY_ACCESS_LIMITED, headers).map(Boolean::parseBoolean).ifPresentOrElse(
builder::organisationEinheitenIdCheckNecessary,
() -> builder.organisationEinheitenIdCheckNecessary(false));
// TODO throw exception if missing required data as soon all clients are fine
// with using headers for auth data.
getFromHeaders(KEY_CLIENT_NAME, headers).ifPresentOrElse(builder::clientName, () -> LOG.warn("Missing client name in grpc header."));
return builder.build();
}
}
// TODO move to a grpcUtil class in common
static Optional<String> getFromHeaders(String key, Metadata headers) {
return Optional.ofNullable(headers.get(createKeyOf(key))).map(val -> new String(val, StandardCharsets.UTF_8));
}
// TODO move to a grpcUtil class in common
static Collection<String> getCollection(String key, Metadata headers) {
return Optional.ofNullable(headers.getAll(createKeyOf(key)))
.map(vals -> StreamSupport.stream(vals.spliterator(), false))
.orElseGet(Stream::empty)
.map(bytes -> new String(bytes, StandardCharsets.UTF_8))
.toList();
}
// TODO move to a grpcUtil class in common
static Key<byte[]> createKeyOf(String key) {
return Key.of(key, Metadata.BINARY_BYTE_MARSHALLER);
}
}
package de.itvsh.kop.user.common;
package de.itvsh.kop.user.common.callcontext;
import java.io.IOException;
......@@ -12,19 +12,23 @@ import org.apache.logging.log4j.CloseableThreadContext;
@Provider
public class HttpRequestInterceptor implements ReaderInterceptor {
private static final String REQUEST_ID_KEY = "requestId";
private static final String REQUEST_ID_PLACEHOLDER = "no-requestId-given";
static final String REQUEST_ID_KEY = "requestId";
static final String REQUEST_ID_PLACEHOLDER = "no-requestId-given";
@Override
public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
var requestId = context.getHeaders().getFirst(REQUEST_ID_KEY);
Object obj = null;
try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.put(REQUEST_ID_KEY,
StringUtils.isNotEmpty(requestId) ? requestId : REQUEST_ID_PLACEHOLDER)) {
try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.put(REQUEST_ID_KEY, getRequestId(context))) {
obj = context.proceed();
}
return obj;
}
String getRequestId(ReaderInterceptorContext context) {
var requestId = context.getHeaders().getFirst(REQUEST_ID_KEY);
return StringUtils.isNotEmpty(requestId) ? requestId : REQUEST_ID_PLACEHOLDER;
}
}
package de.itvsh.kop.user.common.callcontext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.ext.Provider;
import org.eclipse.microprofile.jwt.JsonWebToken;
@Provider
@PreMatching
public class HttpSecurityFilter implements ContainerRequestFilter {
public static final String ORGANSIATIONSEINHEIT_IDS_CLAIM = "organisationseinheitIds";
public static final String USERID_CLAIM = "userId";
@Inject
CurrentCallContextUserService userService;
@Inject
JsonWebToken jwt;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
userService.setCallContextUser(createCallContextUser());
}
CallContextUser createCallContextUser() {
var builder = CallContextUser.builder()
.authenticated(true)
.userName(Optional.ofNullable(jwt.getSubject()))
.organisatorischeEinheitenIds(getOrganisationseinheitIds())
.userId(getUserId());
return builder.build();
}
@SuppressWarnings("unchecked")
List<String> getOrganisationseinheitIds() {
List<String> organisationseinheitIds = new ArrayList<>();
var claimValue = jwt.getClaim(ORGANSIATIONSEINHEIT_IDS_CLAIM);
if (Objects.nonNull(claimValue)) {
organisationseinheitIds.addAll((Collection<String>) claimValue);
}
return organisationseinheitIds;
}
private Optional<String> getUserId() {
var claimValue = jwt.getClaim(USERID_CLAIM);
if (Objects.nonNull(claimValue)) {
return Optional.of(claimValue.toString());
}
return Optional.empty();
}
}
......@@ -8,7 +8,6 @@ quarkus:
origins: http://localhost:4300
kop:
keycloak:
url: https://sso.dev.ozg-sh.de/auth
sync:
cron: "* */10 * * * ?"
api:
......
package de.itvsh.kop.user.common.callcontext;
import java.util.UUID;
import org.bson.types.ObjectId;
import com.thedeanda.lorem.LoremIpsum;
import io.grpc.Metadata;
public class CallContextMetadataTestFactory {
public static final String CLIENT = "testclient-0817";
public static final String ID = new ObjectId().toHexString();
public static final String NAME = LoremIpsum.getInstance().getName();
public static final String ORGANISATORISCHE_EINHEITEN_ID = "0815";
public static final String REQUEST_ID = UUID.randomUUID().toString();
public static final Boolean DO_ORGA_ID_ACCESS_CHECK = Boolean.TRUE;
public static Metadata createMetadata() {
var result = new Metadata();
result.put(GrpcCallContextInterceptor.createKeyOf(GrpcCallContextInterceptor.KEY_USER_ID), ID.getBytes());
result.put(GrpcCallContextInterceptor.createKeyOf(GrpcCallContextInterceptor.KEY_USER_NAME), NAME.getBytes());
result.put(GrpcCallContextInterceptor.createKeyOf(GrpcCallContextInterceptor.KEY_CLIENT_NAME), CLIENT.getBytes());
result.put(GrpcCallContextInterceptor.createKeyOf(GrpcCallContextInterceptor.KEY_ACCESS_LIMITED_ORGAID),
ORGANISATORISCHE_EINHEITEN_ID.getBytes());
result.put(GrpcCallContextInterceptor.createKeyOf(GrpcCallContextInterceptor.KEY_REQUEST_ID), REQUEST_ID.getBytes());
result.put(GrpcCallContextInterceptor.createKeyOf(GrpcCallContextInterceptor.KEY_ACCESS_LIMITED),
DO_ORGA_ID_ACCESS_CHECK.toString().getBytes());
return result;
}
}
package de.itvsh.kop.user.common.callcontext;
import java.util.List;
import java.util.Optional;
public class CallContextUserTestFactory {
static final String NAME = CallContextMetadataTestFactory.NAME;
static final String ID = CallContextMetadataTestFactory.ID;
static final List<String> ORGANISATORISCHE_EINHEITEN_ID = List.of(CallContextMetadataTestFactory.ORGANISATORISCHE_EINHEITEN_ID);
public static CallContextUser create() {
return createBuilder().build();
}
public static CallContextUser.CallContextUserBuilder createBuilder() {
return CallContextUser.builder()
.clientName(CallContextMetadataTestFactory.CLIENT)
.userId(Optional.of(CallContextMetadataTestFactory.ID))
.userName(Optional.of(CallContextMetadataTestFactory.NAME))
.organisatorischeEinheitenId(CallContextMetadataTestFactory.ORGANISATORISCHE_EINHEITEN_ID)
.authenticated(true)
.organisationEinheitenIdCheckNecessary(CallContextMetadataTestFactory.DO_ORGA_ID_ACCESS_CHECK);
}
}
package de.itvsh.kop.user.common.callcontext;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.Spy;
class CurrentCallContextUserServiceTest {
@Spy
private CurrentCallContextUserService userService;
@Nested
class TestService {
CallContextUser user = CallContextUserTestFactory.create();
@BeforeEach
void init() {
userService.setCallContextUser(user);
}
@Test
void shouldGetUser() {
assertThat(userService.getCurrentCallContextUser()).isPresent().get().isEqualTo(user);
}
}
}
package de.itvsh.kop.user.common.callcontext;
import static de.itvsh.kop.user.common.callcontext.GrpcCallContextInterceptor.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
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.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import de.itvsh.kop.user.common.callcontext.GrpcCallContextInterceptor.LogContextSettingListener;
import io.grpc.Metadata;
import io.grpc.ServerCall;
class CallContextHandleInterceptorTest {
@InjectMocks
private GrpcCallContextInterceptor interceptor;
@Mock
private ServerCall.Listener<Object> delegate;
@Spy
private CurrentCallContextUserService userService;
@Nested
class TestCallListener {
private LogContextSettingListener<?> listener;
private Metadata headers = CallContextMetadataTestFactory.createMetadata();
@BeforeEach
void createListener() {
listener = spy(interceptor.new LogContextSettingListener<>(delegate, headers));
}
@Nested
class TestGetRequestId {
@Test
void shouldReturnIdFromHeader() {
var reqId = listener.getRequestId();
assertThat(reqId).isEqualTo(CallContextMetadataTestFactory.REQUEST_ID);
}
@Test
void shouldReturnNewRequestIdIfNoGiven() {
headers.removeAll(createKeyOf(KEY_REQUEST_ID));
var reqId = listener.getRequestId();
assertThat(reqId).isNotBlank().isNotEqualTo(CallContextMetadataTestFactory.REQUEST_ID);
}
}
@DisplayName("Map headers to user")
@Nested
class TestHeadersToUser {
@Test
void shouldFilledUser() {
var user = buildListener().createCallContextUser();
assertThat(user).usingRecursiveComparison().isEqualTo(CallContextUserTestFactory.create());
}
@Test
void shouldFillOrgaIdCollection() {
Metadata metadata = CallContextMetadataTestFactory.createMetadata();
metadata.put(createKeyOf(KEY_ACCESS_LIMITED_ORGAID), "orgaid_2".getBytes());
var user = buildListener(metadata).createCallContextUser();
assertThat(user.getOrganisatorischeEinheitenIds()).hasSize(2).contains(
CallContextMetadataTestFactory.ORGANISATORISCHE_EINHEITEN_ID,
"orgaid_2");
}
@Test
void shouldFillEmptyListIfNoOrgaIds() {
Metadata metadata = CallContextMetadataTestFactory.createMetadata();
metadata.removeAll(createKeyOf(KEY_ACCESS_LIMITED_ORGAID));
var user = buildListener(metadata).createCallContextUser();
assertThat(user.getOrganisatorischeEinheitenIds()).isEmpty();
}
@DisplayName("for key isOrganisationEinheitenIdCheckNecessary")
@Nested
class TestIsOrganisationEinheitenIdCheckNecessary {
@Test
void shouldMapValueIfKeyIsPresent() {
var metadata = CallContextMetadataTestFactory.createMetadata();
var user = buildListener(metadata).createCallContextUser();
assertThat(user.isOrganisationEinheitenIdCheckNecessary()).isTrue();
}
@Test
void shouldMapFalseIfKeyIsNotPresent() {
var metadata = CallContextMetadataTestFactory.createMetadata();
metadata.removeAll(createKeyOf(KEY_ACCESS_LIMITED));
var user = buildListener(metadata).createCallContextUser();
assertThat(user.isOrganisationEinheitenIdCheckNecessary()).isFalse();
}
}
}
@Nested
class TestStartSecurityContext {
@Test
void shouldHaveAuthenticatedAuthorization() {
listener.startSecurityContext();
var userOptional = userService.getCurrentCallContextUser();
assertThat(userOptional).isPresent();
assertThat(userOptional.get().isAuthenticated()).isTrue();
}
}
@Nested
class TestDoSurround {
private Runnable mockRunnable = mock(Runnable.class);
@Test
void shouldRunRunnable() {
listener.doSurroundOn(mockRunnable);
verify(mockRunnable).run();
}
@Test
void shouldStartSecurityContext() {
listener.doSurroundOn(mockRunnable);
verify(listener).startSecurityContext();
}
@Test
void shouldClearSecurityContext() {
listener.doSurroundOn(mockRunnable);
// verify(listener).clearSecurityContext();
}
@Test
void shouldClearSecurityContextOnException() {
var testException = new RuntimeException() {
};
assertThatThrownBy(() -> listener.doSurroundOn(() -> {
throw testException;
})).isSameAs(testException);
// verify(listener).clearSecurityContext();
}
}
@Nested
class TestOnFunctions {
private LogContextSettingListener<Object> listener;
@BeforeEach
void initListener() {
listener = buildListener();
}
@Test
void onMessageShouldCallSurround() {
Object message = mock(Object.class);
listener.onMessage(message);
verify(listener).doSurroundOn(any());
}
@Test
void onHalfCloseShouldCallSurround() {
listener.onHalfClose();
verify(listener).doSurroundOn(any());
}
@Test
void onCancelShouldCallSurround() {
listener.onCancel();
verify(listener).doSurroundOn(any());
}
@Test
void onCompleteShouldCallSurround() {
listener.onComplete();
verify(listener).doSurroundOn(any());
}
@Test
void onReadyShouldCallSurround() {
listener.onReady();
verify(listener).doSurroundOn(any());
}
}
private LogContextSettingListener<Object> buildListener() {
return buildListener(headers);
}
private LogContextSettingListener<Object> buildListener(Metadata headers) {
return spy(interceptor.new LogContextSettingListener<Object>(delegate, headers));
}
}
}
package de.itvsh.kop.user.common.callcontext;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.List;
import java.util.UUID;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.ext.ReaderInterceptorContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Spy;
import de.itvsh.kop.user.common.callcontext.HttpRequestInterceptor;
class HttpRequestInterceptorTest {
@Spy
private HttpRequestInterceptor interceptor;
@Nested
class TestInterceptor {
@Mock
private ReaderInterceptorContext context;
@Nested
class WithRequestId {
String id = UUID.randomUUID().toString();
@BeforeEach
void initHeader() {
var headers = new MultivaluedHashMap<String, String>();
headers.put(HttpRequestInterceptor.REQUEST_ID_KEY, List.of(id));
when(context.getHeaders()).thenReturn(headers);
}
@Test
void shouldSetRequestId() {
var requestId = interceptor.getRequestId(context);
assertThat(requestId).isEqualTo(id);
}
}
@Nested
class WithoutRequestId {
@BeforeEach
void initHeader() {
var headers = new MultivaluedHashMap<String, String>();
headers.put("xxx", List.of("y"));
when(context.getHeaders()).thenReturn(headers);
}
@Test
void shouldSetDummyRequestId() {
var requestId = interceptor.getRequestId(context);
assertThat(requestId).isEqualTo(HttpRequestInterceptor.REQUEST_ID_PLACEHOLDER);
}
}
}
}
package de.itvsh.kop.user.common.callcontext;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
class HttpSecurityFilterTest {
@Spy
@InjectMocks
private HttpSecurityFilter securityFilter;
@Mock
private JsonWebToken token;
@Mock
private CurrentCallContextUserService contextUserService;
@Mock
private ContainerRequestContext requestContext;
@Nested
class TestSettingUser {
@Test
void shouldSetUser() throws IOException {
when(token.getClaim(HttpSecurityFilter.USERID_CLAIM)).thenReturn(CallContextUserTestFactory.ID);
when(token.getClaim(HttpSecurityFilter.ORGANSIATIONSEINHEIT_IDS_CLAIM))
.thenReturn(CallContextUserTestFactory.ORGANISATORISCHE_EINHEITEN_ID);
securityFilter.filter(requestContext);
verify(contextUserService).setCallContextUser(any());
}
}
@Nested
class TestCreateCallContextUser {
@BeforeEach
void init() {
when(token.getClaim(HttpSecurityFilter.USERID_CLAIM)).thenReturn(CallContextUserTestFactory.ID);
when(token.getSubject()).thenReturn(CallContextUserTestFactory.NAME);
when(token.getClaim(HttpSecurityFilter.ORGANSIATIONSEINHEIT_IDS_CLAIM))
.thenReturn(CallContextUserTestFactory.ORGANISATORISCHE_EINHEITEN_ID);
}
@Test
void shouldBeAuthenticated() {
var user = securityFilter.createCallContextUser();
assertThat(user.isAuthenticated()).isTrue();
}
@Test
void shouldHaveUserId() {
var user = securityFilter.createCallContextUser();
assertThat(user.getUserId()).isPresent().get().isEqualTo(CallContextUserTestFactory.ID);
}
@Test
void shouldHaveUserName() {
var user = securityFilter.createCallContextUser();
assertThat(user.getUserName()).isPresent().get().isEqualTo(CallContextUserTestFactory.NAME);
}
@Test
void shouldHaveOrganistaionsEinheitenIds() {
var user = securityFilter.createCallContextUser();
assertThat(user.getOrganisatorischeEinheitenIds()).isNotEmpty();
}
@Test
void shouldNotHaveUserName() {
when(token.getSubject()).thenReturn(null);
var user = securityFilter.createCallContextUser();
assertThat(user.getUserName()).isNotPresent();
}
}
}
package de.itvsh.kop.user.settings;
import io.quarkus.test.junit.QuarkusTestProfile;
import java.util.Map;
import io.quarkus.test.junit.QuarkusTestProfile;
public class UserSettingsResourceTestProfile implements QuarkusTestProfile {
@Override
......
......@@ -6,7 +6,6 @@ import static org.mockito.Mockito.*;
import java.util.Optional;
import de.itvsh.kop.user.settings.UserSettingsService;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
......@@ -16,8 +15,6 @@ import de.itvsh.kop.user.User;
import de.itvsh.kop.user.UserRepository;
import de.itvsh.kop.user.UserTestFactory;
import de.itvsh.kop.user.common.errorhandling.ResourceNotFoundException;
import de.itvsh.kop.user.settings.NotificationsSendFor;
import de.itvsh.kop.user.settings.UserSettings;
public class UserSettingsServiceTest {
@InjectMocks
......@@ -53,6 +50,5 @@ public class UserSettingsServiceTest {
assertThat(updatedUserSettings.getNotificationsSendFor()).isEqualTo(NotificationsSendFor.NONE);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment