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

OZG-6867 OZG-6901 implement sync service

parent 5f35a647
Branches
Tags
No related merge requests found
Showing
with 516 additions and 4 deletions
......@@ -29,6 +29,7 @@ public class OrganisationsEinheit {
private String uebergeordneteOrganisationseinheitId;
private List<String> untergeordneteOrganisationseinheitIds;
private SyncResult syncResult;
private String signature;
@JsonIgnore
private String zufiId;
......
package de.ozgcloud.admin.organisationseinheit;
import java.util.Optional;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
@Repository
interface OrganisationsEinheitRepository extends MongoRepository<OrganisationsEinheit, String> {
Optional<OrganisationsEinheit> findByOrganisationsEinheitIdAndSyncResultIsNotNull(String organisationsEinheitId);
}
......@@ -24,5 +24,4 @@ class OrganisationsEinheitService {
public OrganisationsEinheit getOrganisationsEinheitById(String id) {
return repository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Organisationseinheit with id " + id + " not found"));
}
}
package de.ozgcloud.admin.organisationseinheit;
import java.util.List;
import org.springframework.stereotype.Service;
import de.ozgcloud.admin.keycloak.Group;
import de.ozgcloud.admin.keycloak.KeycloakRemoteService;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
class SyncService {
private final OrganisationsEinheitRepository repository;
private final KeycloakRemoteService keycloakRemoteService;
private final OrganisationsEinheitRemoteService organisationsRemoteService;
public void syncOrganisationsEinheitenFromKeycloak() {
keycloakRemoteService.getGroups().forEach(group -> syncGroups(List.of(group), null));
}
void syncGroups(List<Group> groups, Group parentGroup) {
groups.forEach(group -> syncGroups(group.getSubGroups(), group));
groups.stream().map(group -> syncGroup(group, parentGroup)).forEach(this::saveSyncedOrganisationsEinheit);
}
OrganisationsEinheit syncGroup(Group group, Group parentGroup) {
var pvogOrganisationsEinheiten = organisationsRemoteService.getByOrganisationsEinheitId(group.getOrganisationsEinheitId());
var untergeordneteOrganisationseinheitIds = group.getSubGroups().stream().map(Group::getOrganisationsEinheitId).toList();
var syncedName = syncName(pvogOrganisationsEinheiten, group);
var syncResult = evaluateSyncResult(pvogOrganisationsEinheiten, group);
var organisationsEinheitBuilder = OrganisationsEinheit.builder()
.name(syncedName)
.organisationsEinheitId(group.getOrganisationsEinheitId())
.untergeordneteOrganisationseinheitIds(untergeordneteOrganisationseinheitIds)
.syncResult(syncResult);
if (parentGroup != null) {
organisationsEinheitBuilder.uebergeordneteOrganisationseinheitId(parentGroup.getOrganisationsEinheitId());
}
return organisationsEinheitBuilder.build();
}
String syncName(List<OrganisationsEinheit> pvogOrganisationsEinheiten, Group group) {
if (pvogOrganisationsEinheiten.size() != 1) {
return group.getName();
}
return pvogOrganisationsEinheiten.getFirst().getName();
}
SyncResult evaluateSyncResult(List<OrganisationsEinheit> pvogOrganisationsEinheiten, Group group) {
if (pvogOrganisationsEinheiten.isEmpty()) {
return SyncResult.NOT_FOUND_IN_PVOG;
}
if (pvogOrganisationsEinheiten.size() > 1) {
return SyncResult.ORGANISATIONSEINHEIT_ID_NOT_UNIQUE;
}
if (!pvogOrganisationsEinheiten.getFirst().getName().equals(group.getName())) {
return SyncResult.NAME_MISMATCH;
}
return SyncResult.OK;
}
void saveSyncedOrganisationsEinheit(OrganisationsEinheit syncedOrganisationsEinheit) {
var existingOrganisationsEinheit = repository.findByOrganisationsEinheitIdAndSyncResultIsNotNull(
syncedOrganisationsEinheit.getOrganisationsEinheitId());
repository.save(existingOrganisationsEinheit
.map(OrganisationsEinheit::getSignature)
.map(signature -> syncedOrganisationsEinheit.toBuilder().signature(signature).build())
.orElse(syncedOrganisationsEinheit));
}
}
......@@ -2,7 +2,7 @@ package de.ozgcloud.admin.keycloak;
import java.util.List;
class GroupTestFactory {
public class GroupTestFactory {
public static final String NAME = GroupRepresentationTestFactory.NAME;
public static final String ORGANISATIONS_EINHEIT_ID = GroupRepresentationTestFactory.ORGANISATIONS_EINHEIT_ID;
......
package de.ozgcloud.admin.organisationseinheit;
import static org.assertj.core.api.Assertions.*;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import de.ozgcloud.common.test.DbInitializer;
@DataMongoTest
@ContextConfiguration(initializers = { DbInitializer.class }, classes = { OrganisationsEinheitRepository.class, MongoOperations.class })
@ActiveProfiles({ "itcase", "with_db" })
@EnableAutoConfiguration
class OrganisationsEinheitRepositoryITCase {
@Autowired
private OrganisationsEinheitRepository repository;
@Autowired
private MongoOperations operations;
@BeforeEach
void clearDatabase() {
operations.dropCollection(OrganisationsEinheit.class);
}
@Nested
class TestFindByOrganisationsEinheitIdAndSyncResultIsNull {
@Test
void shouldReturnEmptyOnEmptyDatabase() {
var organisationsEinheit = repository.findByOrganisationsEinheitIdAndSyncResultIsNotNull(
OrganisationsEinheitTestFactory.ORGANISATIONS_EINHEIT_ID);
assertThat(organisationsEinheit).isEmpty();
}
@Test
void shouldReturnEmptyOnNotFoundOrganisationsEinheitId() {
operations.save(OrganisationsEinheitTestFactory.createBuilder().id(null).build());
var organisationsEinheit = repository.findByOrganisationsEinheitIdAndSyncResultIsNotNull("not_found");
assertThat(organisationsEinheit).isEmpty();
}
@Test
void shouldReturnEmptyOnNotFoundSyncResultNull() {
operations.save(OrganisationsEinheitTestFactory.createBuilder().id(null).syncResult(null).build());
var organisationsEinheit = repository.findByOrganisationsEinheitIdAndSyncResultIsNotNull(
OrganisationsEinheitTestFactory.ORGANISATIONS_EINHEIT_ID);
assertThat(organisationsEinheit).isEmpty();
}
@Test
void shouldFind() {
operations.save(OrganisationsEinheitTestFactory.createBuilder().id(null).build());
operations.save(OrganisationsEinheitTestFactory.createBuilder().id(null).organisationsEinheitId(UUID.randomUUID().toString()).build());
var organisationsEinheit = repository.findByOrganisationsEinheitIdAndSyncResultIsNotNull(
OrganisationsEinheitTestFactory.ORGANISATIONS_EINHEIT_ID);
assertThat(organisationsEinheit)
.isNotEmpty()
.get()
.extracting(OrganisationsEinheit::getOrganisationsEinheitId)
.isEqualTo(OrganisationsEinheitTestFactory.ORGANISATIONS_EINHEIT_ID);
}
}
}
\ No newline at end of file
......@@ -11,10 +11,12 @@ 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 org.springframework.data.rest.webmvc.ResourceNotFoundException;
class OrganisationsEinheitServiceTest {
@Spy
@InjectMocks
private OrganisationsEinheitService service;
......@@ -104,5 +106,4 @@ class OrganisationsEinheitServiceTest {
.hasMessage("Organisationseinheit with id not_exists not found");
}
}
}
\ No newline at end of file
......@@ -14,6 +14,7 @@ public class OrganisationsEinheitTestFactory {
public static final List<String> UNTERGEORDNETE_ORGANISATIONSEINHEIT_ID = List.of(UUID.randomUUID().toString());
public static final String ZUFI_ID = UUID.randomUUID().toString();
public static final SyncResult SYNC_RESULT = SyncResult.OK;
public static final String SIGNATURE = "Mit freundlichen Grüßen";
public static OrganisationsEinheit create() {
return createBuilder().build();
......@@ -27,7 +28,8 @@ public class OrganisationsEinheitTestFactory {
.uebergeordneteOrganisationseinheitId(UEBERGEORDNETE_ORGANISATIONSEINHEIT_ID)
.untergeordneteOrganisationseinheitIds(UNTERGEORDNETE_ORGANISATIONSEINHEIT_ID)
.zufiId(ZUFI_ID)
.syncResult(SYNC_RESULT);
.syncResult(SYNC_RESULT)
.signature(SIGNATURE);
}
}
package de.ozgcloud.admin.organisationseinheit;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import de.ozgcloud.admin.keycloak.Group;
import de.ozgcloud.admin.keycloak.GroupTestFactory;
import de.ozgcloud.admin.keycloak.KeycloakRemoteService;
class SyncServiceTest {
@Spy
@InjectMocks
private SyncService service;
@Mock
private OrganisationsEinheitRepository repository;
@Mock
private KeycloakRemoteService keycloakRemoteService;
@Mock
private OrganisationsEinheitRemoteService organisationsEinheitRemoteService;
@Nested
class TestSyncOrganisationsEinheitenFromKeycloak {
private final Group group = GroupTestFactory.create();
@BeforeEach
void setUp() {
when(keycloakRemoteService.getGroups()).thenReturn(Stream.of(group));
doNothing().when(service).syncGroups(anyList(), any());
}
@Test
void shouldGetGroupsFromKeycloak() {
service.syncOrganisationsEinheitenFromKeycloak();
verify(keycloakRemoteService).getGroups();
}
@Test
void shouldSyncGroupsFromKeycloak() {
service.syncOrganisationsEinheitenFromKeycloak();
verify(service).syncGroups(List.of(group), null);
}
}
@Nested
class TestSyncGroups {
private final Group group = GroupTestFactory.create();
private final OrganisationsEinheit syncedOrganisationsEinheitGroup = OrganisationsEinheitTestFactory.create();
private final OrganisationsEinheit syncedOrganisationsEinheitSubGroup = OrganisationsEinheitTestFactory.createBuilder()
.organisationsEinheitId(
UUID.randomUUID().toString()).build();
@BeforeEach
void setUp() {
doNothing().when(service).saveSyncedOrganisationsEinheit(any());
doReturn(syncedOrganisationsEinheitGroup).when(service).syncGroup(group, null);
doReturn(syncedOrganisationsEinheitSubGroup).when(service).syncGroup(group.getSubGroups().getFirst(), group);
}
@Test
void shouldSyncSubGroups() {
service.syncGroups(List.of(group), null);
verify(service).syncGroups(group.getSubGroups(), group);
}
@Test
void shouldSyncSubGroup() {
service.syncGroups(List.of(group), null);
verify(service).syncGroup(group.getSubGroups().getFirst(), group);
}
@Test
void shouldSyncParentGroup() {
service.syncGroups(List.of(group), null);
verify(service).syncGroup(group, null);
}
@Test
void shouldSaveSyncedOrganisationsEinheitForSubGroup() {
service.syncGroups(List.of(group), null);
verify(service).saveSyncedOrganisationsEinheit(syncedOrganisationsEinheitSubGroup);
}
@Test
void shouldSaveSyncedOrganisationsEinheitForGroup() {
service.syncGroups(List.of(group), null);
verify(service).saveSyncedOrganisationsEinheit(syncedOrganisationsEinheitGroup);
}
}
@Nested
class TestSyncGroup {
private final Group group = GroupTestFactory.create();
private final OrganisationsEinheit pvogOrganisationsEinheit = OrganisationsEinheitTestFactory.createBuilder().zufiId(null).signature(null)
.uebergeordneteOrganisationseinheitId(null).untergeordneteOrganisationseinheitIds(null).syncResult(null).build();
@Nested
class ParentGroup {
@BeforeEach
void setUp() {
doReturn(OrganisationsEinheitTestFactory.NAME).when(service).syncName(anyList(), any());
doReturn(SyncResult.OK).when(service).evaluateSyncResult(anyList(), any());
when(organisationsEinheitRemoteService.getByOrganisationsEinheitId(GroupTestFactory.ORGANISATIONS_EINHEIT_ID)).thenReturn(
List.of(pvogOrganisationsEinheit));
}
@Test
void shouldSyncName() {
service.syncGroup(group, null);
verify(service).syncName(List.of(pvogOrganisationsEinheit), group);
}
@Test
void shouldEvaluateSyncResult() {
service.syncGroup(group, null);
verify(service).evaluateSyncResult(List.of(pvogOrganisationsEinheit), group);
}
@Test
void shouldGetOrganisationsEinheit() {
service.syncGroup(group, null);
verify(organisationsEinheitRemoteService).getByOrganisationsEinheitId(GroupTestFactory.ORGANISATIONS_EINHEIT_ID);
}
@Test
void shouldSetUntergeordneteOrganisationseinheitIds() {
var synced = service.syncGroup(group, null);
assertThat(synced.getUntergeordneteOrganisationseinheitIds()).contains(GroupTestFactory.SUB_GROUP_ORGANISATIONS_EINHEIT_ID);
}
}
@Nested
class SubGroup {
@BeforeEach
void setUp() {
doReturn(OrganisationsEinheitTestFactory.NAME).when(service).syncName(anyList(), any());
doReturn(SyncResult.OK).when(service).evaluateSyncResult(anyList(), any());
when(organisationsEinheitRemoteService.getByOrganisationsEinheitId(GroupTestFactory.SUB_GROUP_ORGANISATIONS_EINHEIT_ID)).thenReturn(
List.of(pvogOrganisationsEinheit));
}
@Test
void shouldSyncName() {
service.syncGroup(group.getSubGroups().getFirst(), group);
verify(service).syncName(List.of(pvogOrganisationsEinheit), group.getSubGroups().getFirst());
}
@Test
void shouldEvaluateSyncResult() {
service.syncGroup(group.getSubGroups().getFirst(), group);
verify(service).evaluateSyncResult(List.of(pvogOrganisationsEinheit), group.getSubGroups().getFirst());
}
@Test
void shouldGetOrganisationsEinheit() {
service.syncGroup(group.getSubGroups().getFirst(), group);
verify(organisationsEinheitRemoteService).getByOrganisationsEinheitId(GroupTestFactory.SUB_GROUP_ORGANISATIONS_EINHEIT_ID);
}
@Test
void shouldSetUntergeordneteOrganisationseinheitIds() {
var synced = service.syncGroup(group.getSubGroups().getFirst(), group);
assertThat(synced.getUntergeordneteOrganisationseinheitIds()).isEmpty();
}
@Test
void shouldSetUebergeordneteOrganisationseinheitId() {
var synced = service.syncGroup(group.getSubGroups().getFirst(), group);
assertThat(synced.getUebergeordneteOrganisationseinheitId()).contains(GroupTestFactory.ORGANISATIONS_EINHEIT_ID);
}
}
}
@Nested
class TestSyncName {
@Test
void shouldReturnPvogName() {
var name = service.syncName(List.of(OrganisationsEinheitTestFactory.create()), GroupTestFactory.create());
assertThat(name).isEqualTo(OrganisationsEinheitTestFactory.NAME);
}
@Test
void shouldReturnGroupNameIfOrganisatonsEinheitNotFoundInPvog() {
var name = service.syncName(Collections.emptyList(), GroupTestFactory.create());
assertThat(name).isEqualTo(GroupTestFactory.NAME);
}
@Test
void shouldReturnGroupNameIfMultipleOrganisatonsEinheitenFoundInPvog() {
var name = service.syncName(List.of(OrganisationsEinheitTestFactory.create(), OrganisationsEinheitTestFactory.create()),
GroupTestFactory.create());
assertThat(name).isEqualTo(GroupTestFactory.NAME);
}
}
@Nested
class TestEvaluateSyncResult {
@Test
void shouldReturnOk() {
var syncResult = service.evaluateSyncResult(List.of(OrganisationsEinheitTestFactory.createBuilder().name(GroupTestFactory.NAME).build()),
GroupTestFactory.create());
assertThat(syncResult).isEqualTo(SyncResult.OK);
}
@Test
void shouldReturnNotFoundInPvog() {
var syncResult = service.evaluateSyncResult(Collections.emptyList(), GroupTestFactory.create());
assertThat(syncResult).isEqualTo(SyncResult.NOT_FOUND_IN_PVOG);
}
@Test
void shouldReturnNameMismatch() {
var syncResult = service.evaluateSyncResult(List.of(OrganisationsEinheitTestFactory.create()), GroupTestFactory.create());
assertThat(syncResult).isEqualTo(SyncResult.NAME_MISMATCH);
}
@Test
void shouldReturnOrganisationseinheitIdNotUnique() {
var syncResult = service.evaluateSyncResult(List.of(OrganisationsEinheitTestFactory.create(), OrganisationsEinheitTestFactory.create()),
GroupTestFactory.create());
assertThat(syncResult).isEqualTo(SyncResult.ORGANISATIONSEINHEIT_ID_NOT_UNIQUE);
}
}
@Nested
class TestSaveSyncedOrganisationsEinheit {
private final OrganisationsEinheit syncedOrganisationsEinheit = OrganisationsEinheitTestFactory.createBuilder().id(null).signature(null)
.build();
@Test
void shouldFindSyncedOrganisationsEinheitInDatabase() {
service.saveSyncedOrganisationsEinheit(syncedOrganisationsEinheit);
verify(repository).findByOrganisationsEinheitIdAndSyncResultIsNotNull(syncedOrganisationsEinheit.getOrganisationsEinheitId());
}
@Nested
class SyncedOrganisationsEinheitDoesNotExist {
@BeforeEach
void setUp() {
when(repository.findByOrganisationsEinheitIdAndSyncResultIsNotNull(
syncedOrganisationsEinheit.getOrganisationsEinheitId())).thenReturn(Optional.empty());
}
@Test
void shouldSave() {
service.saveSyncedOrganisationsEinheit(syncedOrganisationsEinheit);
verify(repository).save(syncedOrganisationsEinheit);
}
}
@Nested
class SyncedOrganisationsEinheitExists {
private final OrganisationsEinheit existingOrganisationsEinheit = OrganisationsEinheitTestFactory.create();
@Captor
private ArgumentCaptor<OrganisationsEinheit> savedOrganisationsEinheitArgumentCaptor;
@BeforeEach
void setUp() {
when(repository.findByOrganisationsEinheitIdAndSyncResultIsNotNull(
syncedOrganisationsEinheit.getOrganisationsEinheitId())).thenReturn(Optional.of(existingOrganisationsEinheit));
}
@Test
void shouldSaveSyncedOrganisationsEinheitWithSignature() {
service.saveSyncedOrganisationsEinheit(syncedOrganisationsEinheit);
verify(repository).save(savedOrganisationsEinheitArgumentCaptor.capture());
assertThat(savedOrganisationsEinheitArgumentCaptor.getValue())
.extracting(
OrganisationsEinheit::getOrganisationsEinheitId,
OrganisationsEinheit::getSignature,
OrganisationsEinheit::getId,
OrganisationsEinheit::getName,
OrganisationsEinheit::getSyncResult,
OrganisationsEinheit::getUebergeordneteOrganisationseinheitId,
OrganisationsEinheit::getUntergeordneteOrganisationseinheitIds,
OrganisationsEinheit::getZufiId)
.containsExactly(
syncedOrganisationsEinheit.getOrganisationsEinheitId(),
existingOrganisationsEinheit.getSignature(),
null,
syncedOrganisationsEinheit.getName(),
syncedOrganisationsEinheit.getSyncResult(),
syncedOrganisationsEinheit.getUebergeordneteOrganisationseinheitId(),
syncedOrganisationsEinheit.getUntergeordneteOrganisationseinheitIds(),
syncedOrganisationsEinheit.getZufiId()
);
}
}
}
}
\ 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