Skip to content
Snippets Groups Projects
Commit 6f38c7d3 authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-3276-CleanupRestInterfaceAndNaming' (#37) from...

Merge pull request 'OZG-3276-CleanupRestInterfaceAndNaming' (#37) from OZG-3276-CleanupRestInterfaceAndNaming into master

Reviewed-on: https://git.ozg-sh.de/mgm/user-manager/pulls/37
parents 1bb14aaf 707b10ff
No related branches found
No related tags found
No related merge requests found
Showing
with 315 additions and 421 deletions
......@@ -57,8 +57,8 @@ public class User {
public static final String LASTNAME_FIELD = "lastName";
public static final String FIRSTNAME_FIELD = "firstName";
public static final String USERNAME_FIELD = "username";
static final String ORGANISATIONS_EINHEIT_IDS_FIELD = "organisationsEinheitIds";
static final String NOTIFICATION_SEND_FOR_FIELD = "userSettings.notificationsSendFor";
public static final String ORGANISATIONS_EINHEIT_IDS_FIELD = "organisationsEinheitIds";
public static final String NOTIFICATION_SEND_FOR_FIELD = "userSettings.notificationsSendFor";
@JsonIgnore
@BsonId
......
/*
* Copyright (C) 2022 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.itvsh.kop.user;
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import de.itvsh.kop.common.logging.KopLogging;
@KopLogging
@Path(UserIdResource.PATH_MIGRATION)
public class UserIdResource {
static final String PATH_MIGRATION = "/migration/user"; // NOSONAR
@Inject
UserService userService;
@GET
@Path("/{id}")
@PermitAll
public String findByExternalId(@PathParam(value = "id") String id) {
return userService.findByExternalId(id).getId().toHexString();
}
}
......@@ -25,7 +25,6 @@ package de.itvsh.kop.user;
import static de.itvsh.kop.user.User.*;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
......@@ -35,12 +34,12 @@ import org.bson.types.ObjectId;
import de.itvsh.kop.common.logging.KopLogging;
import de.itvsh.kop.user.common.errorhandling.ResourceNotFoundException;
import de.itvsh.kop.user.settings.NotificationsSendFor;
import io.quarkus.mongodb.panache.PanacheMongoRepository;
@ApplicationScoped
@KopLogging
class UserRepository implements PanacheMongoRepository<User> {
private static final String LIKE_OR = " like ?1 or ";
private static final String SEARCH_QUERY = LASTNAME_FIELD + LIKE_OR +
FIRSTNAME_FIELD + LIKE_OR +
......@@ -48,8 +47,6 @@ class UserRepository implements PanacheMongoRepository<User> {
EMAIL_FIELD + " like ?1";
private static final String AND_DELETED = " and deleted = ?2";
private static final String SEARCH_RECIPIENT_QUERY = ORGANISATIONS_EINHEIT_IDS_FIELD + " = ?1 and " + NOTIFICATION_SEND_FOR_FIELD + " = ?2";
private static final String UPDATE_UNSYNCED_USER_QUERY = LAST_SYNC_TIMESTAMP_FIELD + " < ?1";
public User updateUser(User userToUpdate) {
......@@ -80,10 +77,6 @@ class UserRepository implements PanacheMongoRepository<User> {
return find(SEARCH_QUERY + AND_DELETED, "/.*" + query + "*/i", deleted).range(0, limit - 1).stream();
}
public List<User> findRecipientByOrganisationsEinheitId(String organisationseinheitId) {
return find(SEARCH_RECIPIENT_QUERY, organisationseinheitId, NotificationsSendFor.ALL.name()).list();
}
public long updateUnsyncedUsers(long lastSyncTimestamp) {
return update(DELETED_FIELD, true).where(UPDATE_UNSYNCED_USER_QUERY, lastSyncTimestamp);
}
......
......@@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
......@@ -68,7 +69,7 @@ public abstract class UserResourceMapper {
Date mapCreatedAt(UserResource userRes) {
var createdAt = userRes.toRepresentation().getCreatedTimestamp();
return createdAt != null ? new Date(createdAt) : new Date();
return Optional.ofNullable(createdAt).map(Date::new).orElse(new Date());
}
Set<String> mapOrganisationsEinheitIds(UserResource userRes) {
......@@ -79,10 +80,7 @@ public abstract class UserResourceMapper {
private List<String> getOrganisationsEinheitIdsFromGroups(List<GroupRepresentation> groups) {
return groups.stream()
.map(group -> {
var groupFromRealm = realm.getGroupByPath(group.getPath());
return groupFromRealm != null ? groupFromRealm.getAttributes() : null;
})
.map(this::mapGroup)
.filter(Objects::nonNull)
.map(attributeMap -> attributeMap.get(properties.organisationsEinheitIdKey()))
.filter(Objects::nonNull)
......@@ -90,6 +88,12 @@ public abstract class UserResourceMapper {
.toList();
}
private Map<String, List<String>> mapGroup(GroupRepresentation group) {
var groupFromRealm = realm.getGroupByPath(group.getPath());
return Optional.ofNullable(groupFromRealm).map(GroupRepresentation::getAttributes).orElse(null);
}
List<String> mapRoles(UserResource userRes) {
var roleRepresentation = Optional.ofNullable(userRes.roles().getAll().getClientMappings())
.filter(Objects::nonNull)
......
......@@ -23,7 +23,6 @@
*/
package de.itvsh.kop.user;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
......@@ -81,14 +80,10 @@ public class UserService {
repository.updateUnsyncedUsers(lastSyncTimestamp);
}
public List<User> findRecipientByOrganisationsEinheitId(String organisationsEinheitId) {
return repository.findRecipientByOrganisationsEinheitId(organisationsEinheitId);
}
public User getById(String id) {
if (id.contains(UUID_PATTERN)) {
// TODO wenn user migriert wurden wieder entfernen.
return repository.findByExternalId(id).orElseThrow(() -> new ResourceNotFoundException(User.class, id));
return findByExternalId(id);
}
return repository.findById(id).orElseThrow(() -> new ResourceNotFoundException(User.class, id));
......
......@@ -10,7 +10,7 @@ import io.grpc.Metadata;
import io.grpc.Metadata.Key;
// TODO move to a grpcUtil class in common
public class GrpcUtil {
class GrpcUtil {
public static Optional<String> getFromHeaders(String key, Metadata headers) {
return Optional.ofNullable(headers.get(createKeyOf(key)))
......
/*
* Copyright (C) 2022 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.itvsh.kop.user.common.errorhandling;
public class KeycloakClientException extends TechnicalException {
private static final long serialVersionUID = 1L;
private static final String MESSAGE_TEMPLATE = "Access Denied for admin user: %s, realm: %s, url: %s";
public KeycloakClientException(String user, String realm, String url, Throwable cause) {
super(String.format(MESSAGE_TEMPLATE, user, realm, url), cause);
}
}
\ No newline at end of file
/*
* Copyright (C) 2022 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.itvsh.kop.user.common.errorhandling;
public class UserNotFoundException extends TechnicalException {
private static final long serialVersionUID = 1L;
private static final String MESSAGE_WITH_EXTERNALID_TEMPLATE = "User not found for keycloak id %s";
private static final String MESSAGE_WITH_ID_TEMPLATE = "User not found for id %s";
public UserNotFoundException(String id) {
super(String.format(MESSAGE_WITH_ID_TEMPLATE, id));
}
public UserNotFoundException(String externalId, Throwable cause) {
super(String.format(MESSAGE_WITH_EXTERNALID_TEMPLATE, externalId), cause);
}
}
\ No newline at end of file
......@@ -33,11 +33,11 @@ import javax.inject.Inject;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.ProcessingException;
import de.itvsh.kop.common.logging.KopLogging;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.UserRepresentation;
import de.itvsh.kop.common.logging.KopLogging;
import de.itvsh.kop.user.RemoteUserIterator;
import de.itvsh.kop.user.User;
import de.itvsh.kop.user.UserResourceMapper;
......@@ -74,7 +74,7 @@ class KeycloakApiService {
return mapper.toKopUser(realmResource.users().get(userRepresentation.getId()));
}
private <T> T handlingKeycloakException(Supplier<T> runnable) {
<T> T handlingKeycloakException(Supplier<T> runnable) {
try {
return runnable.get();
} catch (ClientErrorException | ProcessingException | IllegalStateException e) {
......
......@@ -24,7 +24,6 @@
package de.itvsh.kop.user.recipient;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
......@@ -45,14 +44,13 @@ public class RecipientGrpcService extends RecipientServiceImplBase {
@Override
public void findRecipientByOrganisationsEinheitId(GrpcFindRecipientRequest request, StreamObserver<GrpcFindRecipientResponse> responseObserver) {
List<User> recipients = recipientService.findRecipientByOrganisationsEinheitId(request.getOrganisationsEinheitId());
var recipients = recipientService.findByOrganisationsEinheitId(request.getOrganisationsEinheitId());
responseObserver.onNext(buildSearchReponse(recipients.stream().map(recipientMapper::toRecipient).toList()));
responseObserver.onNext(buildSearchReponse(recipients));
responseObserver.onCompleted();
}
private GrpcFindRecipientResponse buildSearchReponse(Collection<GrpcRecipient> recipients) {
return GrpcFindRecipientResponse.newBuilder().addAllRecipient(recipients).build();
private GrpcFindRecipientResponse buildSearchReponse(Collection<User> recipients) {
return GrpcFindRecipientResponse.newBuilder().addAllRecipient(recipients.stream().map(recipientMapper::toRecipient).toList()).build();
}
}
\ No newline at end of file
package de.itvsh.kop.user.recipient;
import static de.itvsh.kop.user.User.*;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import de.itvsh.kop.common.logging.KopLogging;
import de.itvsh.kop.user.User;
import de.itvsh.kop.user.settings.NotificationsSendFor;
import io.quarkus.mongodb.panache.PanacheMongoRepository;
@ApplicationScoped
@KopLogging
class RecipientRepository implements PanacheMongoRepository<User> {
private static final String SEARCH_RECIPIENT_QUERY = ORGANISATIONS_EINHEIT_IDS_FIELD + " = ?1 and " + NOTIFICATION_SEND_FOR_FIELD + " = ?2";
public List<User> findByOrganisationsEinheitId(String organisationseinheitId) {
return find(SEARCH_RECIPIENT_QUERY, organisationseinheitId, NotificationsSendFor.ALL.name()).list();
}
}
\ No newline at end of file
......@@ -31,7 +31,6 @@ import javax.inject.Inject;
import com.cronutils.utils.StringUtils;
import de.itvsh.kop.user.User;
import de.itvsh.kop.user.UserService;
import de.itvsh.kop.user.common.errorhandling.FunctionalException;
@ApplicationScoped
......@@ -40,12 +39,12 @@ class RecipientService {
static final String MISSING_ORGANISATIONS_EINHEIT_ID_MESSAGE_TEMPLATE = "OrganisationsEinheitId ('%s') can not be null or empty";
@Inject
UserService userService;
RecipientRepository repository;
public List<User> findRecipientByOrganisationsEinheitId(String organisationsEinheitId) {
public List<User> findByOrganisationsEinheitId(String organisationsEinheitId) {
if (StringUtils.isEmpty(organisationsEinheitId)) {
throw new FunctionalException(() -> String.format(MISSING_ORGANISATIONS_EINHEIT_ID_MESSAGE_TEMPLATE, organisationsEinheitId));
}
return userService.findRecipientByOrganisationsEinheitId(organisationsEinheitId);
return repository.findByOrganisationsEinheitId(organisationsEinheitId);
}
}
\ No newline at end of file
......@@ -31,7 +31,7 @@ import javax.inject.Inject;
import de.itvsh.kop.user.UserService;
@ApplicationScoped
public class UserSettingsService {
class UserSettingsService {
@Inject
UserService userService;
......@@ -43,10 +43,6 @@ public class UserSettingsService {
return repository.updateByUserId(userId, userSettings);
}
public UserSettings findByUserId(String userId) {
return userService.getById(userId).getUserSettings();
}
public UserSettings getByUserId(String userId) {
var user = userService.getById(userId);
......
......@@ -25,6 +25,7 @@ package de.itvsh.kop.user.userprofile;
import javax.inject.Inject;
import de.itvsh.kop.user.User;
import de.itvsh.kop.user.UserService;
import de.itvsh.kop.user.grpc.userprofile.GrpcGetUserProfileRequest;
import de.itvsh.kop.user.grpc.userprofile.GrpcGetUserProfileResponse;
......@@ -44,7 +45,11 @@ public class UserProfileGrpcService extends UserProfileServiceImplBase {
public void getById(GrpcGetUserProfileRequest request, StreamObserver<GrpcGetUserProfileResponse> responseObserver) {
var userProfile = service.getById(request.getUserId());
responseObserver.onNext(GrpcGetUserProfileResponse.newBuilder().setUserProfile(mapper.mapTo(userProfile)).build());
responseObserver.onNext(buildResponse(userProfile));
responseObserver.onCompleted();
}
private GrpcGetUserProfileResponse buildResponse(User userProfile) {
return GrpcGetUserProfileResponse.newBuilder().setUserProfile(mapper.mapTo(userProfile)).build();
}
}
\ No newline at end of file
/*
* Copyright (C) 2022 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.itvsh.kop.user;
import static io.restassured.RestAssured.*;
import static org.hamcrest.CoreMatchers.*;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;
import io.quarkus.test.junit.mockito.InjectMock;
@QuarkusTest
@TestProfile(UserProfileResourceTestProfile.class)
class UserIdResourceITCase {
private static final String EXTERNAL_ID_PATH = UserIdResource.PATH_MIGRATION + "/{id}";
@InjectMock
UserService userService;
@Test
void shouldGetInternalIdByExternalId() {
when(userService.findByExternalId(UserTestFactory.EXTERNAL_ID)).thenReturn(UserTestFactory.createWithId());
given()
.when().get(EXTERNAL_ID_PATH, UserTestFactory.EXTERNAL_ID)
.then()
.statusCode(200).body(is(UserTestFactory.ID.toHexString()));
}
}
......@@ -23,7 +23,6 @@
*/
package de.itvsh.kop.user;
import static de.itvsh.kop.user.UserTestFactory.*;
import static org.assertj.core.api.Assertions.*;
import java.util.List;
......@@ -48,33 +47,31 @@ class UserProfileResourceAssemblerTest {
@Nested
class TestToUserProfileResource {
private static final User USER = createWithId();
@Test
void shouldAddSelfLink() {
var res = assembler.toUserProfileResource(USER, USER_MANAGER_URL);
var res = assembler.toUserProfileResource(UserTestFactory.create(), USER_MANAGER_URL);
assertThat(res.getLinks().get(UserProfileResourceAssembler.REL_SELF))
.isNotNull()
.hasFieldOrPropertyWithValue("href",
USER_MANAGER_URL + UserProfileResource.USER_PROFILE_RESOURCE_PATH_TEMPLATE.replace("{id}", ID.toHexString()));
USER_MANAGER_URL + UserProfileResource.USER_PROFILE_RESOURCE_PATH_TEMPLATE.replace("{id}", UserTestFactory.ID_STR));
}
@Test
void shouldAddSettingsLink() {
var res = assembler.toUserProfileResource(USER, USER_MANAGER_URL);
var res = assembler.toUserProfileResource(UserTestFactory.create(), USER_MANAGER_URL);
assertThat(res.getLinks().get(UserProfileResourceAssembler.REL_SETTINGS))
.isNotNull()
.hasFieldOrPropertyWithValue("href",
USER_MANAGER_URL + UserSettingsResource.SETTINGS_LINK_PATTERN.replace("{id}", ID.toHexString()));
USER_MANAGER_URL + UserSettingsResource.SETTINGS_LINK_PATTERN.replace("{id}", UserTestFactory.ID_STR));
}
}
@DisplayName("To Userprofile Resource List")
@Nested
class TestToUserProfileResourceList {
private static final List<User> USERS = List.of(createWithId(), createWithId());
private static final List<User> USERS = List.of(UserTestFactory.create(), UserTestFactory.create());
@Test
void shouldAddSelfLink() {
......
......@@ -26,8 +26,8 @@ package de.itvsh.kop.user;
import static de.itvsh.kop.user.UserTestFactory.*;
import static io.restassured.RestAssured.*;
import static org.hamcrest.CoreMatchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import java.util.stream.Stream;
......@@ -55,15 +55,18 @@ class UserProfileResourceITCase {
@InjectMock
UserService userService;
private String settingsUrlWithUserId = HTTP_LOCALHOST + UserSettingsResource.SETTINGS_LINK_PATTERN.replace("{id}", ID.toHexString());
private String urlWithUserId = HTTP_LOCALHOST + UserProfileResource.USER_PROFILE_RESOURCE_PATH_TEMPLATE.replace("{id}", ID.toHexString());
private String settingsUrlWithUserId = HTTP_LOCALHOST
+ UserSettingsResource.SETTINGS_LINK_PATTERN.replace("{id}", UserTestFactory.ID_STR);
private String urlWithUserId = HTTP_LOCALHOST
+ UserProfileResource.USER_PROFILE_RESOURCE_PATH_TEMPLATE.replace("{id}", UserTestFactory.ID_STR);
@DisplayName("Test get user by id")
@Nested
class TestGetUser {
@BeforeEach
void init() {
when(userService.getById(any())).thenReturn(createWithId());
when(userService.getById(any())).thenReturn(UserTestFactory.create());
}
@Test
......@@ -71,7 +74,7 @@ class UserProfileResourceITCase {
given()
.when()
.accept(RestMediaType.APPLICATION_HAL_JSON)
.get(UserProfileResource.USERS_PATH + "/{id}", ID.toHexString())
.get(UserProfileResource.USERS_PATH + "/{id}", UserTestFactory.ID_STR)
.then().statusCode(200)
.body("_links.self.href", equalTo(urlWithUserId));
}
......@@ -81,7 +84,7 @@ class UserProfileResourceITCase {
given()
.when()
.accept(RestMediaType.APPLICATION_HAL_JSON)
.get(UserProfileResource.USERS_PATH + "/{id}", ID.toHexString())
.get(UserProfileResource.USERS_PATH + "/{id}", UserTestFactory.ID_STR)
.then().statusCode(200)
.body("_links.settings.href", equalTo(settingsUrlWithUserId));
}
......@@ -111,7 +114,7 @@ class UserProfileResourceITCase {
@BeforeEach
void init() {
when(userService.findUsers(any(), anyInt())).thenReturn(Stream.of(createWithId()));
when(userService.findUsers(any(), anyInt())).thenReturn(Stream.of(UserTestFactory.create()));
}
@Test
......@@ -180,8 +183,8 @@ class UserProfileResourceITCase {
@Test
void shouldGetDeletedAndNotDeletedUsers() {
User user1 = UserTestFactory.createBuilder().deleted(false).build();
User user2 = UserTestFactory.createBuilder().deleted(true).build();
var user1 = UserTestFactory.createBuilder().deleted(false).build();
var user2 = UserTestFactory.createBuilder().deleted(true).build();
when(userService.findUsers(anyString(), anyInt())).thenReturn(Stream.of(user1, user2));
given()
......@@ -202,7 +205,7 @@ class UserProfileResourceITCase {
@BeforeEach
void init() {
when(userService.findUsers(any(), anyInt())).thenReturn(Stream.of(createWithId()));
when(userService.findUsers(any(), anyInt())).thenReturn(Stream.of(UserTestFactory.create()));
}
@Test
......
......@@ -23,15 +23,16 @@
*/
package de.itvsh.kop.user;
import static de.itvsh.kop.user.settings.NotificationsSendFor.*;
import static java.util.function.Predicate.not;
import static org.assertj.core.api.Assertions.*;
import java.time.Instant;
import java.util.List;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
......@@ -40,7 +41,6 @@ import org.junit.jupiter.api.Test;
import com.thedeanda.lorem.LoremIpsum;
import de.itvsh.kop.user.common.MongoDbTestProfile;
import de.itvsh.kop.user.settings.UserSettings;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;
......@@ -51,25 +51,11 @@ class UserRepositoryITCase {
@Inject
UserRepository repository;
private User user1;
private User user2;
@BeforeEach
void init() {
repository.deleteAll();
user1 = UserTestFactory.create();
repository.persist(user1);
user2 = UserTestFactory.createBuilder().externalId("unknown").build();
repository.persist(user2);
user2 = user2.toBuilder().externalId(null).build();
}
@DisplayName("Update unsynced users")
@Nested
class TestUpdateUnsyncedUser {
private long lastSyncTimestamp = Instant.now().toEpochMilli();
private static final long NOW = Instant.now().toEpochMilli();
@BeforeEach
void init() {
......@@ -78,18 +64,18 @@ class UserRepositoryITCase {
@Test
void shouldMarkUnsyncedUserAsDeleted() {
repository.persist(createUserWithLastSyncTimestamp(lastSyncTimestamp - 1000));
repository.persist(createUserWithLastSyncTimestamp(NOW - 1000));
repository.updateUnsyncedUsers(lastSyncTimestamp);
repository.updateUnsyncedUsers(NOW);
assertThat(getFirstUser().isDeleted()).isTrue();
}
@Test
void shouldNotMarkUserIfSynced() {
repository.persist(createUserWithLastSyncTimestamp(lastSyncTimestamp));
repository.persist(createUserWithLastSyncTimestamp(NOW));
repository.updateUnsyncedUsers(lastSyncTimestamp);
repository.updateUnsyncedUsers(NOW);
assertThat(getFirstUser().isDeleted()).isFalse();
}
......@@ -99,215 +85,241 @@ class UserRepositoryITCase {
}
private User getFirstUser() {
var allUser = repository.findAll();
return allUser.list().get(0);
return repository.findAll().list().get(0);
}
}
@DisplayName("Find Users")
@DisplayName("Find all active user")
@Nested
class TestFindUsers {
private static final int LIMIT_5 = 5;
class TestFindAllActiveUser {
@BeforeEach
void init() {
repository.deleteAll();
repository.persist(UserTestFactory.createBuilder().email(LoremIpsum.getInstance().getEmail()).externalId("additional-id").build());
user1 = UserTestFactory.create();
repository.persist(user1);
repository.persist(UserTestFactory.create());
}
@Test
void shouldFindByLastName() {
var res = repository.findUsers(UserTestFactory.LAST_NAME, false, LIMIT_5);
var user = findAllActiveUser(UserTestFactory.LAST_NAME);
assertThat(res).isNotEmpty().hasSize(2);
assertThat(user).isNotEmpty().hasSize(1);
}
@Test
void shouldFindCaseInsensitive() {
var user = findAllActiveUser(UserTestFactory.LAST_NAME.toLowerCase());
assertThat(user).isNotEmpty().hasSize(1);
}
@Test
void shouldFindByFirstName() {
var res = repository.findUsers(UserTestFactory.FIRST_NAME, false, LIMIT_5);
var user = findAllActiveUser(UserTestFactory.FIRST_NAME);
assertThat(res).isNotEmpty().hasSize(2);
assertThat(user).isNotEmpty().hasSize(1);
}
@Test
void shouldFindByUsername() {
var res = repository.findUsers(UserTestFactory.USER_NAME, false, LIMIT_5);
var user = findAllActiveUser(UserTestFactory.USER_NAME);
assertThat(res).isNotEmpty().hasSize(2);
assertThat(user).isNotEmpty().hasSize(1);
}
@Test
void shouldFindByUsernamePart() {
var res = repository.findUsers(UserTestFactory.USER_NAME.substring(0, 4), false, LIMIT_5);
var user = findAllActiveUser(UserTestFactory.USER_NAME.substring(0, 4));
assertThat(res).isNotEmpty().hasSize(2);
assertThat(user).isNotEmpty().hasSize(1);
}
@Test
void shouldFindByEmail() {
var res = repository.findUsers(UserTestFactory.EMAIL, false, LIMIT_5);
var user = findAllActiveUser(UserTestFactory.EMAIL);
assertThat(res).isNotEmpty().hasSize(1);
assertThat(user).isNotEmpty().hasSize(1);
}
@Test
void shouldNotFind() {
var res = repository.findUsers("xxx", false, 5);
assertThat(res).isEmpty();
void shouldReturnEmptyListIfNotMatch() {
var user = findAllActiveUser("xxx");
assertThat(user).isEmpty();
}
@Test
void shouldFindCaseInsensitive() {
var res = repository.findUsers(UserTestFactory.LAST_NAME.toLowerCase(), false, LIMIT_5);
assertThat(res).isNotEmpty().hasSize(2);
private Stream<User> findAllActiveUser(String query) {
return repository.findUsers(query, false, 5);
}
@Test
void shouldFindByExternalId() {
var res = repository.findByExternalId(user1.getExternalId());
void shouldFindNotDeletedUsers() {
User user1 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Max").deleted(true).build();
User user2 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Maximilian").deleted(true).build();
User user3 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Maximus").deleted(false).build();
assertThat(res).isPresent();
assertThat(res.get().getExternalId()).isEqualTo(user1.getExternalId());
}
repository.persist(user1);
repository.persist(user2);
repository.persist(user3);
@Test
void shouldFindById() {
var res = repository.findById(user1.getId());
var foundUsers = findAllActiveUser("Max").toList();
assertThat(res).isNotNull();
assertThat(res.getId()).isEqualTo(user1.getId());
foundUsers.forEach(u -> assertThat(u.isDeleted()).isFalse());
}
@Test
void shouldFindByEmailOnly() {
var res = repository.findByEmail(user1.getEmail());
void shouldUseLimit() {
repository.persist(UserTestFactory.createBuilder().id(new ObjectId()).build());
assertThat(res).isPresent();
assertThat(res.get().getExternalId()).isEqualTo(user1.getExternalId());
var res = repository.findUsers(UserTestFactory.LAST_NAME.toLowerCase(), false, 2);
assertThat(res).isNotEmpty().hasSize(2);
}
}
@Test
void shouldNotFindByEmptyEmail() {
var res = repository.findByEmail(null);
@DisplayName("Find all")
@Nested
class TestFindAll {
assertThat(res).isEmpty();
@BeforeEach
void init() {
repository.deleteAll();
repository.persist(UserTestFactory.createBuilder().id(new ObjectId()).email(LoremIpsum.getInstance().getEmail())
.externalId("additional-id").build());
repository.persist(UserTestFactory.create());
}
@Test
void shouldFindDeletedUsers() {
User user1 = UserTestFactory.createBuilder().firstName("Max").deleted(true).build();
User user2 = UserTestFactory.createBuilder().firstName("Maximilian").deleted(true).build();
User user3 = UserTestFactory.createBuilder().firstName("Maximus").deleted(false).build();
void shouldFindDeletedAndNotDeletedUsers() {
User user1 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Max").deleted(true).build();
User user2 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Maximilian").deleted(true).build();
User user3 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Maximus").deleted(false).build();
repository.persist(user1);
repository.persist(user2);
repository.persist(user3);
var foundUsers = repository.findUsers("Max", true, 10).toList();
var foundUsers = repository.findUsers("Max", 10).toList();
assertThat(foundUsers).hasSize(2);
foundUsers.forEach(u -> assertThat(u.isDeleted()).isTrue());
assertThat(foundUsers).hasSizeGreaterThan(2);
List<User> startWithMax = foundUsers.stream().filter(u -> u.getFirstName().startsWith("Max")).toList();
assertThat(startWithMax).hasSize(3);
assertThat(startWithMax.stream().filter(User::isDeleted).count()).isEqualTo(2);
assertThat(startWithMax.stream().filter(not(User::isDeleted)).count()).isEqualTo(1);
}
}
@Test
void shouldFindNotDeletedUsers() {
User user1 = UserTestFactory.createBuilder().firstName("Max").deleted(true).build();
User user2 = UserTestFactory.createBuilder().firstName("Maximilian").deleted(true).build();
User user3 = UserTestFactory.createBuilder().firstName("Maximus").deleted(false).build();
@DisplayName("Find all inactive user")
@Nested
class TestFindAllInactiveUser {
@BeforeEach
void init() {
repository.deleteAll();
User user1 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Max").deleted(true).build();
User user2 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Maximilian").deleted(true).build();
User user3 = UserTestFactory.createBuilder().id(new ObjectId()).firstName("Maximus").deleted(false).build();
repository.persist(user1);
repository.persist(user2);
repository.persist(user3);
var foundUsers = repository.findUsers("Max", false, 10).toList();
foundUsers.forEach(u -> assertThat(u.isDeleted()).isFalse());
}
@Test
void shouldFindDeletedAndNotDeletedUsers() {
User user1 = UserTestFactory.createBuilder().firstName("Max").deleted(true).build();
User user2 = UserTestFactory.createBuilder().firstName("Maximilian").deleted(true).build();
User user3 = UserTestFactory.createBuilder().firstName("Maximus").deleted(false).build();
void shouldFindDeletedUsers() {
var foundUsers = repository.findUsers("Max", true, 10).toList();
repository.persist(user1);
repository.persist(user2);
repository.persist(user3);
assertThat(foundUsers).hasSize(2);
foundUsers.forEach(u -> assertThat(u.isDeleted()).isTrue());
}
var foundUsers = repository.findUsers("Max", 10).toList();
}
assertThat(foundUsers).hasSizeGreaterThan(2);
List<User> startWithMax = foundUsers.stream().filter(u -> u.getFirstName().startsWith("Max")).toList();
assertThat(startWithMax.size()).isEqualTo(3);
assertThat(startWithMax.stream().filter(User::isDeleted).count()).isEqualTo(2);
assertThat(startWithMax.stream().filter(not(User::isDeleted)).count()).isEqualTo(1);
@DisplayName("Find by externalId")
@Nested
class TestFindByExternalId {
@BeforeEach
void init() {
repository.deleteAll();
repository.persist(UserTestFactory.create());
}
@Test
void shouldFindByOrganisationeinheitIdAndNotificatinoActivated() {
var recipientUser = UserTestFactory.createBuilder().userSettings(new UserSettings(ALL)).build();
var notRecipientUser = UserTestFactory.createBuilder().organisationsEinheitIds(List.of("a")).build();
repository.persist(List.of(notRecipientUser, recipientUser));
void shouldFindByExternalId() {
var user = repository.findByExternalId(UserTestFactory.EXTERNAL_ID);
var users = repository.findRecipientByOrganisationsEinheitId(UserTestFactory.ORGANISTATIONSEINHEITEN_ID);
assertThat(user).isPresent();
assertThat(user.get()).usingRecursiveComparison().isEqualTo(UserTestFactory.create());
}
}
assertThat(users).hasSize(1);
assertThat(users.get(0).getOrganisationsEinheitIds()).contains(UserTestFactory.ORGANISTATIONSEINHEITEN_ID);
@DisplayName("Find by id")
@Nested
class TestFindById {
@BeforeEach
void init() {
repository.deleteAll();
repository.persist(UserTestFactory.create());
}
@Test
void shouldUseLimit() {
repository.persist(UserTestFactory.create());
void shouldFindById() {
var user = repository.findById(UserTestFactory.ID_STR);
var res = repository.findUsers(UserTestFactory.LAST_NAME.toLowerCase(), false, 2);
assertThat(res).isNotEmpty().hasSize(2);
assertThat(user).isNotNull();
assertThat(user.get()).usingRecursiveComparison().isEqualTo(UserTestFactory.create());
}
}
@DisplayName("Test refreshing user")
@DisplayName("Find by email")
@Nested
class TestRefresh {
class TestFindByEmail {
@BeforeEach
void init() {
repository.deleteAll();
repository.persist(UserTestFactory.create());
}
@Test
void shouldRefreshByExternalId() {
var user = repository.refresh(user1.toBuilder().id(null).build());
void shouldFindByEmailOnly() {
var user = repository.findByEmail(UserTestFactory.EMAIL);
assertThat(user).isNotNull().hasFieldOrPropertyWithValue("id", user1.getId());
assertThat(user).isPresent();
assertThat(user.get()).usingRecursiveComparison().isEqualTo(UserTestFactory.create());
}
@Test
void shouldRefreshById() {
var user = repository.refresh(user1);
void shouldNotFindByEmptyEmail() {
var user = repository.findByEmail(null);
assertThat(user).isNotNull().hasFieldOrPropertyWithValue("id", user1.getId());
assertThat(user).isEmpty();
}
}
@DisplayName("Test for empty result list ")
@DisplayName("Test refreshing user")
@Nested
class TestReturnEmptyList {
@Test
void whenIdNotFound() {
var recipientUser = UserTestFactory.createBuilder().userSettings(new UserSettings(ALL)).build();
repository.persist(recipientUser);
var users = repository.findRecipientByOrganisationsEinheitId("some_id");
assertThat(users).isEmpty();
class TestRefresh {
@BeforeEach
void init() {
repository.deleteAll();
repository.persist(UserTestFactory.create());
}
@Test
void whenNotificationDeactivated() {
void shouldRefreshByExternalId() {
var user = repository.refresh(UserTestFactory.createBuilder().id(null).build());
var users = repository.findRecipientByOrganisationsEinheitId(UserTestFactory.ORGANISTATIONSEINHEITEN_ID);
assertThat(users).isEmpty();
assertThat(user).usingRecursiveComparison().ignoringFields("id").isEqualTo(UserTestFactory.create());
}
@Test
void shouldReturnEmptyListNotificationDeactivated() {
var users = repository.findRecipientByOrganisationsEinheitId(UserTestFactory.ORGANISTATIONSEINHEITEN_ID);
void shouldRefreshById() {
var user = repository.refresh(UserTestFactory.create());
assertThat(users).isEmpty();
assertThat(user).usingRecursiveComparison().ignoringFields("id").isEqualTo(UserTestFactory.create());
}
}
}
\ No newline at end of file
......@@ -39,7 +39,6 @@ import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.admin.client.resource.RoleScopeResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.representations.idm.ClientMappingsRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.mapstruct.factory.Mappers;
......@@ -49,6 +48,7 @@ import org.mockito.Mock;
import de.itvsh.kop.user.keycloak.KeycloakApiProperties;
class UserResourceMapperTest {
static final String ORGANISATIONS_EINHEIT_ID_KEY = "organisationseinheitId";
static final String ORGANISATIONS_EINHEIT_ID_1 = "0815";
static final String ORGANISATIONS_EINHEIT_ID_2 = "4711";
......@@ -59,16 +59,17 @@ class UserResourceMapperTest {
static final Map<String, List<String>> ATTRIBUTES_2 = Map.of(ORGANISATIONS_EINHEIT_ID_KEY, List.of(ORGANISATIONS_EINHEIT_ID_2));
@InjectMocks
private UserResourceMapper mapper = Mappers.getMapper(UserResourceMapper.class);
UserResourceMapper mapper = Mappers.getMapper(UserResourceMapper.class);
@Mock
private KeycloakApiProperties properties;
KeycloakApiProperties properties;
@Mock
private RealmResource realm;
RealmResource realm;
@DisplayName("To kop user")
@Nested
class TestMapping {
class TestToKopUser {
@BeforeEach
void init() {
......@@ -84,80 +85,96 @@ class UserResourceMapperTest {
@Test
void shouldMapToUser() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
var user = toKopUser();
assertThat(user).isNotNull();
}
@Test
void shouldMapEmail() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
var user = toKopUser();
assertThat(user.getEmail()).isEqualTo(UserRepresentationTestFactory.EMAIL);
}
@DisplayName("externalId")
@Nested
class TestMapExternalId {
@Test
void shouldMapExternalId() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
void shouldMap() {
var user = toKopUser();
assertThat(user.getExternalId()).isEqualTo(UserRepresentationTestFactory.EXTERNAL_ID);
}
@Test
void shouldMapExternalIdFallback() {
User user = mapper.toKopUser(UserResourceTestFactory.createWithAttributes(Map.of()));
void shouldMapFallbackOnEmptyAttributes() {
var user = toKopUser(UserResourceTestFactory.createWithAttributes(Collections.emptyMap()));
assertThat(user.getExternalId()).isEqualTo(UserRepresentationTestFactory.EXTERNAL_ID_FALLBACK);
}
}
@Test
void shouldMapFirstName() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
var user = toKopUser();
assertThat(user.getFirstName()).isEqualTo(UserRepresentationTestFactory.FIRST_NAME);
}
@Test
void shouldMapLastName() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
var user = toKopUser();
assertThat(user.getLastName()).isEqualTo(UserRepresentationTestFactory.LAST_NAME);
}
@Test
void shouldMapUserName() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
var user = toKopUser();
assertThat(user.getUsername()).isEqualTo(UserRepresentationTestFactory.USER_NAME);
}
@Test
void shouldMapOrganisationsEinheitIds() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
var user = toKopUser();
assertThat(user.getOrganisationsEinheitIds()).isNotEmpty().contains(ORGANISATIONS_EINHEIT_ID_1);
}
@Test
void shouldMapMultipleOrganisationsEinheitIds() {
GroupRepresentation groupRepresentation = GroupRepresentationTestFactory.createByPathAndOrganisationEinheitId(GROUP_2_PATH,
var groupRepresentation = GroupRepresentationTestFactory.createByPathAndOrganisationEinheitId(GROUP_2_PATH,
ORGANISATIONS_EINHEIT_ID_2);
when(realm.getGroupByPath(GROUP_2_PATH)).thenReturn(groupRepresentation);
User user = mapper.toKopUser(
UserResourceTestFactory.createWithGroups(List.of(GroupRepresentationTestFactory.createGroup(UserResourceMapperTest.GROUP_1_PATH),
GroupRepresentationTestFactory.createGroup(UserResourceMapperTest.GROUP_2_PATH))));
var user = toKopUser(buildUserResourceWithGroups());
assertThat(user.getOrganisationsEinheitIds()).isNotEmpty().hasSize(2).contains(ORGANISATIONS_EINHEIT_ID_2);
}
private UserResource buildUserResourceWithGroups() {
return UserResourceTestFactory.createWithGroups(List.of(
GroupRepresentationTestFactory.createGroup(UserResourceMapperTest.GROUP_1_PATH),
GroupRepresentationTestFactory.createGroup(UserResourceMapperTest.GROUP_2_PATH)));
}
@Test
void shouldMapRoles() {
User user = mapper.toKopUser(UserResourceTestFactory.create());
var user = toKopUser();
assertThat(user.getRoles()).isNotEmpty().contains(UserRepresentationTestFactory.ROLE_NAME);
}
private User toKopUser() {
return toKopUser(UserResourceTestFactory.create());
}
private User toKopUser(UserResource userResource) {
return mapper.toKopUser(userResource);
}
}
@DisplayName("Get client roles")
......@@ -165,18 +182,18 @@ class UserResourceMapperTest {
class TestGetClientRoles {
@Mock
private UserResource userResource;
UserResource userResource;
@Mock
private RoleMappingResource roleMappingResource;
RoleMappingResource roleMappingResource;
@Mock
private RoleScopeResource roleScopeResource;
RoleScopeResource roleScopeResource;
@Mock
private MappingsRepresentation mappingsRepresentation;
MappingsRepresentation mappingsRepresentation;
@Mock
private Map<String, ClientMappingsRepresentation> clientMappingsRepresentation;
Map<String, ClientMappingsRepresentation> clientMappingsRepresentation;
@Mock
private ClientMappingsRepresentation clientMappingRepresentation;
ClientMappingsRepresentation clientMappingRepresentation;
@BeforeEach
void init() {
......
......@@ -23,6 +23,7 @@
*/
package de.itvsh.kop.user;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
......@@ -39,6 +40,7 @@ import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import de.itvsh.kop.user.common.errorhandling.ResourceNotFoundException;
import de.itvsh.kop.user.keycloak.KeycloakUserRemoteService;
class UserServiceTest {
......@@ -50,26 +52,64 @@ class UserServiceTest {
@Mock
KeycloakUserRemoteService keycloakRemoteService;
@DisplayName("Find by id")
@DisplayName("Get by id")
@Nested
class TestFindById {
class TestGetById {
@DisplayName("on UUID pattern")
@Nested
class TestByUUID {
private final static String ID = UUID.randomUUID().toString();
@BeforeEach
void mockRepository() {
when(repository.findByExternalId(any())).thenReturn(Optional.of(UserTestFactory.create()));
}
@Test
void shouldCallRepository() {
service.getById(ID);
verify(repository).findByExternalId(anyString());
}
@Test
void shouldFindByIdOnInternalId() {
void shouldThrowExceptionIfNotExists() {
when(repository.findByExternalId(anyString())).thenReturn(Optional.empty());
assertThatThrownBy(() -> service.getById(ID))
.isInstanceOf(ResourceNotFoundException.class)
.extracting(e -> ((ResourceNotFoundException) e).getId()).isEqualTo(ID);
}
}
@DisplayName("on other")
@Nested
class TestByOther {
private final static String ID = "xxx";
@BeforeEach
void mockRepository() {
when(repository.findById(anyString())).thenReturn(Optional.of(UserTestFactory.create()));
}
service.getById("xxx");
@Test
void shouldCallRepository() {
service.getById(ID);
verify(repository).findById(anyString());
}
@Test
void shouldFindByExternalIdOnUUID() {
when(repository.findByExternalId(any())).thenReturn(Optional.of(UserTestFactory.create()));
void shouldThrowExceptionIfNotExists() {
when(repository.findById(anyString())).thenReturn(Optional.empty());
service.getById(UUID.randomUUID().toString());
verify(repository).findByExternalId(anyString());
assertThatThrownBy(() -> service.getById(ID))
.isInstanceOf(ResourceNotFoundException.class)
.extracting(e -> ((ResourceNotFoundException) e).getId()).isEqualTo(ID);
}
}
}
......@@ -81,7 +121,7 @@ class UserServiceTest {
@BeforeEach
void init() {
when(repository.refresh(any())).thenReturn(UserTestFactory.createWithId());
when(repository.refresh(any())).thenReturn(UserTestFactory.create());
}
@Test
......@@ -136,18 +176,6 @@ class UserServiceTest {
}
}
@DisplayName("Find recipient by organisationsEinheitId")
@Nested
class TestFindRecipientByOrganisationsEinheitId {
@Test
void shouldCallRepository() {
service.findRecipientByOrganisationsEinheitId(UserTestFactory.ORGANISTATIONSEINHEITEN_ID);
verify(repository).findRecipientByOrganisationsEinheitId(UserTestFactory.ORGANISTATIONSEINHEITEN_ID);
}
}
@DisplayName("Search users")
@Nested
class TestUserSearch {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment