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

Merge branch 'master' of git.ozg-sh.de:mgm/pluto

# Conflicts:
#	pluto-server/src/main/resources/application-local.yml
parents 550834fa 62cb4927
Branches
Tags
No related merge requests found
Showing
with 428 additions and 181 deletions
...@@ -26,6 +26,8 @@ class IndexedVorgang { ...@@ -26,6 +26,8 @@ class IndexedVorgang {
static final String FIELD_AKTENZEICHEN = "aktenzeichen"; static final String FIELD_AKTENZEICHEN = "aktenzeichen";
static final String FIELD_ORGANISATIONSEINHEITEN_ID = "organisationseinheitenId"; static final String FIELD_ORGANISATIONSEINHEITEN_ID = "organisationseinheitenId";
static final String FIELD_CREATED_AT = "createdAt"; static final String FIELD_CREATED_AT = "createdAt";
static final String FIELD_STATUS = "status";
static final String FIELD_ASSIGNED_TO = "assignedTo";
@Id @Id
private String vorgangId; private String vorgangId;
......
...@@ -14,4 +14,7 @@ class SearchRequest { ...@@ -14,4 +14,7 @@ class SearchRequest {
private int limit; private int limit;
private String query; private String query;
private List<String> organisationseinheitIds; private List<String> organisationseinheitIds;
private List<String> status;
private boolean filterByOrganisationseinheitIds;
private String assignedTo;
} }
package de.itvsh.ozg.pluto.common.search; package de.itvsh.ozg.pluto.common.search;
import static de.itvsh.ozg.pluto.common.search.IndexedVorgang.FIELD_AKTENZEICHEN;
import static de.itvsh.ozg.pluto.common.search.IndexedVorgang.FIELD_ANTRAGSTELLER_NAME;
import static de.itvsh.ozg.pluto.common.search.IndexedVorgang.FIELD_ANTRAGSTELLTER_VORNAME;
import static de.itvsh.ozg.pluto.common.search.IndexedVorgang.FIELD_NAME;
import static de.itvsh.ozg.pluto.common.search.IndexedVorgang.FIELD_ORGANISATIONSEINHEITEN_ID;
import static de.itvsh.ozg.pluto.common.search.IndexedVorgang.FIELD_VORGANG_NUMMER;
import static org.elasticsearch.index.query.AbstractQueryBuilder.DEFAULT_BOOST;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import de.itvsh.ozg.pluto.vorgang.FindVorgangRequest; import de.itvsh.ozg.pluto.vorgang.FindVorgangRequest;
import de.itvsh.ozg.pluto.vorgang.Vorgang; import de.itvsh.ozg.pluto.vorgang.Vorgang;
import de.itvsh.ozg.pluto.vorgang.Vorgang.Status;
import de.itvsh.ozg.pluto.vorgang.VorgangHeader; import de.itvsh.ozg.pluto.vorgang.VorgangHeader;
@Service @Service
@ConditionalOnProperty(prefix = "spring.elasticsearch", name = "uris") @ConditionalOnProperty(prefix = "spring.elasticsearch", name = "uris")
public class SearchService { public class SearchService {
private static final float HALF_BOOST = 0.5f;
private static final float DOUBLE_BOOST = 2f;
private static final Map<String, Float> FIELD_MAP = Map.of(
FIELD_NAME, HALF_BOOST,
FIELD_VORGANG_NUMMER, DOUBLE_BOOST,
FIELD_AKTENZEICHEN, DOUBLE_BOOST,
FIELD_ANTRAGSTELLER_NAME, DEFAULT_BOOST,
FIELD_ANTRAGSTELLTER_VORNAME, DEFAULT_BOOST);
@Autowired @Autowired
private SearchVorgangRepostitory repostitory; private SearchVorgangRepostitory repostitory;
@Autowired @Autowired
private IndexedVorgangMapper mapper; private SearchVorgangCustomRepostitory searchRepostitory;
@Autowired @Autowired
private ElasticsearchOperations elasticsearchOperations; private IndexedVorgangMapper mapper;
public void addVorgang(Vorgang vorgang) { public void addVorgang(Vorgang vorgang) {
repostitory.save(mapper.fromVorgang(vorgang)); repostitory.save(mapper.fromVorgang(vorgang));
...@@ -64,36 +36,16 @@ public class SearchService { ...@@ -64,36 +36,16 @@ public class SearchService {
} }
public Page<VorgangHeader> find(FindVorgangRequest request) { public Page<VorgangHeader> find(FindVorgangRequest request) {
// FIXME search by for POSTSTELLE
var searchRequest = SearchRequest.builder() var searchRequest = SearchRequest.builder()
.limit(request.getLimit()) .limit(request.getLimit())
.offSet(request.getOffset()) .offSet(request.getOffset())
.query(request.getSearchBy()) .query(request.getSearchBy())
.organisationseinheitIds(request.getFilterBy().getOrganisationseinheitIds()) .status(request.getFilterBy().getStatus().stream().map(Status::name).toList())
.build(); .filterByOrganisationseinheitIds(request.getFilterBy().isFilterByOrganisationseinheitenId())
.assignedTo(request.getFilterBy().getAssignedTo())
.organisationseinheitIds(request.getFilterBy().getOrganisationseinheitIds()).build();
return searchBy(searchRequest); return searchRepostitory.searchBy(searchRequest);
} }
Page<VorgangHeader> searchBy(SearchRequest request) {
var pageable = PageRequest.of(request.getOffSet(), request.getLimit());
var searchQuery = createQuery(request, pageable);
var result = elasticsearchOperations.search(searchQuery, IndexedVorgang.class);
var mappedResult = result.get().map(SearchHit::getContent).map(mapper::toVorgangHeader).toList();
return PageableExecutionUtils.getPage(mappedResult, pageable, result::getTotalHits);
}
NativeSearchQuery createQuery(SearchRequest request, PageRequest pageable) {
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
// FIXME security issue - missing orgaId should not lead to deliver all items
if (CollectionUtils.isNotEmpty(request.getOrganisationseinheitIds())) {
searchQueryBuilder.withFilter(boolQuery().must(termsQuery(FIELD_ORGANISATIONSEINHEITEN_ID, request.getOrganisationseinheitIds())));
}
return searchQueryBuilder.withQuery(queryStringQuery("*" + request.getQuery() + "*").fields(FIELD_MAP))
.withPageable(pageable).build();
}
} }
package de.itvsh.ozg.pluto.common.search;
import static de.itvsh.ozg.pluto.common.search.IndexedVorgang.*;
import static org.elasticsearch.index.query.AbstractQueryBuilder.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
import java.util.Arrays;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;
import de.itvsh.ozg.pluto.vorgang.VorgangHeader;
@Repository
class SearchVorgangCustomRepositoryImpl implements SearchVorgangCustomRepostitory {
private static final String KEYWORD = ".keyword";
private static final float HALF_BOOST = 0.5f;
private static final float DOUBLE_BOOST = 2f;
static final Map<String, Float> FIELD_MAP = Map.of(
FIELD_NAME, HALF_BOOST,
FIELD_VORGANG_NUMMER, DOUBLE_BOOST,
FIELD_AKTENZEICHEN, DOUBLE_BOOST,
FIELD_ANTRAGSTELLER_NAME, DEFAULT_BOOST,
FIELD_ANTRAGSTELLTER_VORNAME, DEFAULT_BOOST);
@Autowired
private ElasticsearchOperations elasticsearchOperations;
@Autowired
private IndexedVorgangMapper mapper;
@Override
public Page<VorgangHeader> searchBy(SearchRequest request) {
var pageable = PageRequest.of(request.getOffSet(), request.getLimit());
var searchQuery = createQuery(request, pageable);
var result = elasticsearchOperations.search(searchQuery, IndexedVorgang.class);
var mappedResult = result.get().map(SearchHit::getContent).map(mapper::toVorgangHeader).toList();
return PageableExecutionUtils.getPage(mappedResult, pageable, result::getTotalHits);
}
NativeSearchQuery createQuery(SearchRequest request, PageRequest pageable) {
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
setFilter(request, searchQueryBuilder);
Arrays.stream(request.getQuery().strip().split(" ")).forEach(query -> searchQueryBuilder
.withQuery(queryStringQuery("*" + query + "*").fields(SearchVorgangCustomRepositoryImpl.FIELD_MAP)));
return searchQueryBuilder.withPageable(pageable).build();
}
private boolean dontFilterByOrganisationseinheitIds(SearchRequest request) {
return !request.isFilterByOrganisationseinheitIds();
}
private void setFilter(SearchRequest request, NativeSearchQueryBuilder searchQueryBuilder) {
var query = boolQuery();
if (request.isFilterByOrganisationseinheitIds()) {
addByOrganisationseinheitIdsFilters(request, query);
} else if (CollectionUtils.isNotEmpty(request.getStatus())) {
query.must(termsQuery(FIELD_STATUS + KEYWORD, request.getStatus()));
}
searchQueryBuilder.withFilter(query);
}
private void addByOrganisationseinheitIdsFilters(SearchRequest request, BoolQueryBuilder query) {
query.must(termsQuery(FIELD_ORGANISATIONSEINHEITEN_ID, request.getOrganisationseinheitIds()));
if (CollectionUtils.isNotEmpty(request.getStatus())) {
query.must(termsQuery(FIELD_STATUS + KEYWORD, request.getStatus()));
}
if (StringUtils.isNotEmpty(request.getAssignedTo())) {
query.must(termsQuery(FIELD_ASSIGNED_TO + KEYWORD, request.getAssignedTo()));
}
}
}
package de.itvsh.ozg.pluto.common.search;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.Page;
import de.itvsh.ozg.pluto.vorgang.VorgangHeader;
@ConditionalOnProperty(prefix = "spring.elasticsearch", name = "uris")
interface SearchVorgangCustomRepostitory {
Page<VorgangHeader> searchBy(SearchRequest request);
}
...@@ -5,5 +5,4 @@ import org.springframework.data.elasticsearch.repository.ElasticsearchRepository ...@@ -5,5 +5,4 @@ import org.springframework.data.elasticsearch.repository.ElasticsearchRepository
@ConditionalOnProperty(prefix = "spring.elasticsearch", name = "uris") @ConditionalOnProperty(prefix = "spring.elasticsearch", name = "uris")
interface SearchVorgangRepostitory extends ElasticsearchRepository<IndexedVorgang, String> { interface SearchVorgangRepostitory extends ElasticsearchRepository<IndexedVorgang, String> {
} }
package de.itvsh.ozg.pluto.common.search; package de.itvsh.ozg.pluto.common.search;
import java.io.InputStream;
import java.time.Duration; import java.time.Duration;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
...@@ -54,13 +53,7 @@ class SearchInitializer implements ApplicationContextInitializer<ConfigurableApp ...@@ -54,13 +53,7 @@ class SearchInitializer implements ApplicationContextInitializer<ConfigurableApp
TestPropertyValues.of( TestPropertyValues.of(
"spring.elasticsearch.uris= http://" + container.getHost() + ":" + container.getFirstMappedPort(), "spring.elasticsearch.uris= http://" + container.getHost() + ":" + container.getFirstMappedPort(),
"spring.elasticsearch.username= " + USERNAME, "spring.elasticsearch.username= " + USERNAME,
"spring.elasticserach.password= " + PASSWORD, "spring.elasticsearch.password= " + PASSWORD,
// "kop.elasticsearch.initEnabled=false",
"kop.elasticsearch.index=test").applyTo(applicationContext); "kop.elasticsearch.index=test").applyTo(applicationContext);
} }
private String getRootCa(ElasticsearchContainer container) {
return new String(container.copyFileFromContainer("/usr/share/elasticsearch/config/certs/http_ca.crt", InputStream::readAllBytes));
}
} }
...@@ -2,6 +2,7 @@ package de.itvsh.ozg.pluto.common.search; ...@@ -2,6 +2,7 @@ package de.itvsh.ozg.pluto.common.search;
import org.elasticsearch.core.List; import org.elasticsearch.core.List;
import de.itvsh.ozg.pluto.command.UserTestFactory;
import de.itvsh.ozg.pluto.vorgang.FindVorgangRequestTestFactory; import de.itvsh.ozg.pluto.vorgang.FindVorgangRequestTestFactory;
import de.itvsh.ozg.pluto.vorgang.ZustaendigeStelleTestFactory; import de.itvsh.ozg.pluto.vorgang.ZustaendigeStelleTestFactory;
...@@ -11,6 +12,8 @@ class SearchRequestTestFactory { ...@@ -11,6 +12,8 @@ class SearchRequestTestFactory {
static final String QUERY = "vors"; static final String QUERY = "vors";
static final String ORGANISATIONSEINHEIT_ID = ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID; static final String ORGANISATIONSEINHEIT_ID = ZustaendigeStelleTestFactory.ORGANISATIONSEINHEIT_ID;
static final boolean FILTER_BY_ORGANISATIONSEINHEIT_ID = true;
static final String ASSIGNED_TO = UserTestFactory.ID;
static SearchRequest create() { static SearchRequest create() {
return createBuilder().build(); return createBuilder().build();
...@@ -21,6 +24,8 @@ class SearchRequestTestFactory { ...@@ -21,6 +24,8 @@ class SearchRequestTestFactory {
.limit(LIMIT) .limit(LIMIT)
.offSet(OFFSET) .offSet(OFFSET)
.query(QUERY) .query(QUERY)
.filterByOrganisationseinheitIds(FILTER_BY_ORGANISATIONSEINHEIT_ID)
.assignedTo(ASSIGNED_TO)
.organisationseinheitIds(List.of(ORGANISATIONSEINHEIT_ID)); .organisationseinheitIds(List.of(ORGANISATIONSEINHEIT_ID));
} }
} }
package de.itvsh.ozg.pluto.common.search; package de.itvsh.ozg.pluto.common.search;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.*;
import java.io.IOException; import java.io.IOException;
import java.util.Optional; import java.util.Optional;
...@@ -20,6 +20,9 @@ import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; ...@@ -20,6 +20,9 @@ import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import de.itvsh.ozg.pluto.command.Command; import de.itvsh.ozg.pluto.command.Command;
import de.itvsh.ozg.pluto.command.CommandService; import de.itvsh.ozg.pluto.command.CommandService;
import de.itvsh.ozg.pluto.command.CommandTestFactory; import de.itvsh.ozg.pluto.command.CommandTestFactory;
import de.itvsh.ozg.pluto.command.UserTestFactory;
import de.itvsh.ozg.pluto.vorgang.FilterCriteriaTestFactory;
import de.itvsh.ozg.pluto.vorgang.FindVorgangRequestTestFactory;
import de.itvsh.ozg.pluto.vorgang.Vorgang.Status; import de.itvsh.ozg.pluto.vorgang.Vorgang.Status;
import de.itvsh.ozg.pluto.vorgang.VorgangTestFactory; import de.itvsh.ozg.pluto.vorgang.VorgangTestFactory;
...@@ -78,16 +81,13 @@ public class SearchServiceITCase { ...@@ -78,16 +81,13 @@ public class SearchServiceITCase {
@Nested @Nested
class TestSearchVorgang { class TestSearchVorgang {
// private static final String DATE_1 = "2007-11-03T10:15:30Z";
// private static final String DATE_2 = "2012-11-03T10:15:30Z";
// private static final String DATE_3 = "2022-11-03T10:15:30Z";
@BeforeEach @BeforeEach
void init() { void init() {
elasticsearchOperations.indexOps(IndexedVorgang.class).delete(); elasticsearchOperations.indexOps(IndexedVorgang.class).delete();
searchService.addVorgang(VorgangTestFactory.create()); searchService.addVorgang(VorgangTestFactory.create());
searchService.addVorgang(VorgangTestFactory.createBuilder().id(new ObjectId().toHexString()).aktenzeichen("test").build()); searchService.addVorgang(VorgangTestFactory.createBuilder().id(new ObjectId().toHexString()).aktenzeichen("test")
.assignedTo(UUID.randomUUID().toString()).build());
searchService.addVorgang(VorgangTestFactory.createBuilder().id(new ObjectId().toHexString()).aktenzeichen("vors").build()); searchService.addVorgang(VorgangTestFactory.createBuilder().id(new ObjectId().toHexString()).aktenzeichen("vors").build());
searchService.addVorgang(VorgangTestFactory.createBuilder().id(new ObjectId().toHexString()).aktenzeichen("vOrsi").build()); searchService.addVorgang(VorgangTestFactory.createBuilder().id(new ObjectId().toHexString()).aktenzeichen("vOrsi").build());
...@@ -96,9 +96,14 @@ public class SearchServiceITCase { ...@@ -96,9 +96,14 @@ public class SearchServiceITCase {
elasticsearchOperations.save(IndexedVorgangTestFactory.create(), IndexCoordinates.of("other-test")); elasticsearchOperations.save(IndexedVorgangTestFactory.create(), IndexCoordinates.of("other-test"));
} }
@Nested
class filteredByOrganisationseinheitenId {
@Test @Test
void shouldFind() { void shouldFindByAktenzeichen() {
var res = searchService.searchBy(SearchRequestTestFactory.create()); var res = searchService.find(FindVorgangRequestTestFactory.createBuilder()
.searchBy("vors")
.filterBy(FilterCriteriaTestFactory.createBuilder().clearStatus().assignedTo(null).build())
.build());
assertThat(res).hasSize(2); assertThat(res).hasSize(2);
} }
...@@ -106,18 +111,38 @@ public class SearchServiceITCase { ...@@ -106,18 +111,38 @@ public class SearchServiceITCase {
@Test @Test
void shouldFindByAntragstellerName() { void shouldFindByAntragstellerName() {
var res = searchService var res = searchService
.searchBy(SearchRequestTestFactory.createBuilder().query(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME).build()); .find(FindVorgangRequestTestFactory.createBuilder()
.searchBy(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME)
.filterBy(FilterCriteriaTestFactory.createBuilder().clearStatus().assignedTo(null).build())
.build());
assertThat(res).hasSize(4); assertThat(res).hasSize(4);
} }
@Test
void shouldFindByAntragstellerNameAndAktenzeichen() {
var res = searchService
.find(FindVorgangRequestTestFactory.createBuilder()
.searchBy(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME + " test")
.filterBy(FilterCriteriaTestFactory.createBuilder().clearStatus().assignedTo(null).build())
.build());
assertThat(res).hasSize(1);
}
@Test @Test
void shouldFindByAntragstellerNameAndereOrganisationEinheitId() { void shouldFindByAntragstellerNameAndereOrganisationEinheitId() {
searchService searchService
.addVorgang(VorgangTestFactory.createWithOrganisationEinheitId("12345678").toBuilder().id(UUID.randomUUID().toString()).build()); .addVorgang(
VorgangTestFactory.createWithOrganisationEinheitId("12345678").toBuilder().id(UUID.randomUUID().toString()).build());
var res = searchService.searchBy(SearchRequestTestFactory.createBuilder() var res = searchService.find(FindVorgangRequestTestFactory.createBuilder()
.query(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME).organisationseinheitIds(List.of("12345678")).build()); .searchBy(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME).filterBy(
FilterCriteriaTestFactory.createBuilder()
.clearOrganisationseinheitIds()
.organisationseinheitIds(List.of("12345678"))
.clearStatus().build())
.build());
assertThat(res).hasSize(1); assertThat(res).hasSize(1);
} }
...@@ -125,11 +150,88 @@ public class SearchServiceITCase { ...@@ -125,11 +150,88 @@ public class SearchServiceITCase {
@Test @Test
void shouldDoPageination() { void shouldDoPageination() {
var res = searchService var res = searchService
.searchBy(SearchRequestTestFactory.createBuilder().query(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME).limit(2).build()); .find(FindVorgangRequestTestFactory.createBuilder()
.searchBy(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME)
.limit(2)
.filterBy(FilterCriteriaTestFactory.createBuilder().clearStatus().build())
.build());
assertThat(res).hasSize(2); assertThat(res).hasSize(2);
assertThat(res.getTotalPages()).isEqualTo(2); assertThat(res.getTotalPages()).isEqualTo(2);
} }
} }
@Nested
class filteredForStatus {
@Test
void shouldFindByAntragstellerName() {
searchService
.addVorgang(
VorgangTestFactory.createWithOrganisationEinheitId("12345678").toBuilder().id(UUID.randomUUID().toString()).build());
var res = searchService
.find(FindVorgangRequestTestFactory.createBuilder()
.searchBy(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME)
.filterBy(FilterCriteriaTestFactory.createBuilder().filterByOrganisationseinheitenId(false).build())
.build());
assertThat(res).hasSize(5);
}
}
@Nested
class filteredForStatusAndOrganisationEinheitId {
@BeforeEach
void init() {
searchService
.addVorgang(
VorgangTestFactory.createWithOrganisationEinheitId("12345678").toBuilder().id(UUID.randomUUID().toString()).build());
searchService
.addVorgang(VorgangTestFactory.createBuilder().status(Status.ANGENOMMEN).id(UUID.randomUUID().toString()).build());
}
@Test
void shouldFindByAktenzeichen() {
var res = searchService
.find(FindVorgangRequestTestFactory.createBuilder()
.searchBy("test")
.filterBy(FilterCriteriaTestFactory.createBuilder().assignedTo(null).build())
.build());
assertThat(res).hasSize(1);
}
@Test
void shouldFindByAntragstellerName() {
var res = searchService
.find(FindVorgangRequestTestFactory.createBuilder()
.searchBy(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME)
.filterBy(FilterCriteriaTestFactory.createBuilder().assignedTo(null).build())
.build());
assertThat(res).hasSize(4);
}
}
@Nested
class filteredForAssignedToAndOrganisationEinheitId {
@BeforeEach
void init() {
searchService
.addVorgang(
VorgangTestFactory.createWithOrganisationEinheitId("12345678").toBuilder().id(UUID.randomUUID().toString()).build());
}
@Test
void shouldFindByAntragstellerName() {
var res = searchService
.find(FindVorgangRequestTestFactory.createBuilder()
.searchBy(IndexedVorgangTestFactory.ANTRAGSTELLER_NAME)
.filterBy(FilterCriteriaTestFactory.createBuilder().clearStatus().assignedTo(UserTestFactory.ID).build())
.build());
assertThat(res).hasSize(3);
}
}
}
} }
package de.itvsh.ozg.pluto.common.search; package de.itvsh.ozg.pluto.common.search;
import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.*;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.elasticsearch.core.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import de.itvsh.ozg.pluto.vorgang.VorgangHeader; import de.itvsh.ozg.pluto.vorgang.FindVorgangRequestTestFactory;
import de.itvsh.ozg.pluto.vorgang.VorgangHeaderTestFactory;
import de.itvsh.ozg.pluto.vorgang.VorgangTestFactory; import de.itvsh.ozg.pluto.vorgang.VorgangTestFactory;
class SearchServiceTest { class SearchServiceTest {
...@@ -31,6 +19,10 @@ class SearchServiceTest { ...@@ -31,6 +19,10 @@ class SearchServiceTest {
@Mock @Mock
private SearchVorgangRepostitory repostitory; private SearchVorgangRepostitory repostitory;
@Mock
private SearchVorgangCustomRepostitory searchRepostitory;
@Mock @Mock
private IndexedVorgangMapper mapper; private IndexedVorgangMapper mapper;
...@@ -66,74 +58,11 @@ class SearchServiceTest { ...@@ -66,74 +58,11 @@ class SearchServiceTest {
@Nested @Nested
class TestSearch { class TestSearch {
@Mock
private SearchHits<IndexedVorgang> searchHits;
@Mock
private SearchHit<IndexedVorgang> searchHit;
@BeforeEach
void init() {
when(searchHit.getContent()).thenReturn(IndexedVorgangTestFactory.create());
when(searchHits.get()).thenReturn(List.of(searchHit).stream());
when(operations.search(any(NativeSearchQuery.class), eq(IndexedVorgang.class))).thenReturn(searchHits);
}
@Test @Test
void shouldCallSearch() { void shouldCallSearch() {
searchService.searchBy(SearchRequestTestFactory.create()); searchService.find(FindVorgangRequestTestFactory.create());
verify(mapper, atLeastOnce()).toVorgangHeader(any());
verify(operations).search(any(NativeSearchQuery.class), eq(IndexedVorgang.class));
}
@Test
void shouldMapResult() {
when(mapper.toVorgangHeader(any())).thenReturn(VorgangHeaderTestFactory.create());
var res = searchService.searchBy(SearchRequestTestFactory.create());
assertThat(res).isNotEmpty().hasAtLeastOneElementOfType(VorgangHeader.class); verify(searchRepostitory).searchBy(any(SearchRequest.class));
} }
} }
@Nested
class TestQuery {
@Test
void shouldHaveFilter() {
var request = SearchRequestTestFactory.create();
var query = searchService.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getFilter()).isNotNull();
assertThat(query.getFilter()).asString().contains("organisationseinheitenId");
assertThat(query.getFilter()).asString().contains("08150815");
}
@Test
void shouldHavePaging() {
var request = SearchRequestTestFactory.create();
var query = searchService.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getPageable()).isNotNull();
assertThat(query.getPageable().getOffset()).isZero();
assertThat(query.getPageable().getPageSize()).isEqualTo(SearchRequestTestFactory.LIMIT);
assertThat(query.getPageable().getSort()).isEqualTo(Sort.unsorted());
}
@Test
void shouldHaveQuery() {
var request = SearchRequestTestFactory.create();
var query = searchService.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getQuery()).isNotNull();
assertThat(query.getQuery()).asString().contains("\"query\" : \"*vors*\"");
assertThat(query.getQuery()).asString().contains("aktenzeichen^2.0");
assertThat(query.getQuery()).asString().contains("antragstellerName^1.0");
assertThat(query.getQuery()).asString().contains("antragstellerVorname^1.0");
assertThat(query.getQuery()).asString().contains("vorgangName^0.5");
assertThat(query.getQuery()).asString().contains("vorgangNummer^2.0");
}
}
} }
package de.itvsh.ozg.pluto.common.search;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import org.elasticsearch.core.List;
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.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import de.itvsh.ozg.pluto.vorgang.Vorgang.Status;
import de.itvsh.ozg.pluto.vorgang.VorgangHeader;
import de.itvsh.ozg.pluto.vorgang.VorgangHeaderTestFactory;
class SearchVorgangCustomRepositoryImplTest {
@InjectMocks
private SearchVorgangCustomRepositoryImpl searchRepostitory;
@Mock
private IndexedVorgangMapper mapper;
@Mock
private SearchProperties properties;
@Mock
private ElasticsearchOperations operations;
@Nested
class TestSearch {
@Mock
private SearchHits<IndexedVorgang> searchHits;
@Mock
private SearchHit<IndexedVorgang> searchHit;
@BeforeEach
void init() {
when(searchHit.getContent()).thenReturn(IndexedVorgangTestFactory.create());
when(searchHits.get()).thenReturn(List.of(searchHit).stream());
when(operations.search(any(NativeSearchQuery.class), eq(IndexedVorgang.class))).thenReturn(searchHits);
}
@Test
void shouldCallSearch() {
searchRepostitory.searchBy(SearchRequestTestFactory.create());
verify(mapper, atLeastOnce()).toVorgangHeader(any());
verify(operations).search(any(NativeSearchQuery.class), eq(IndexedVorgang.class));
}
@Test
void shouldMapResult() {
when(mapper.toVorgangHeader(any())).thenReturn(VorgangHeaderTestFactory.create());
var res = searchRepostitory.searchBy(SearchRequestTestFactory.create());
assertThat(res).isNotEmpty().hasAtLeastOneElementOfType(VorgangHeader.class);
}
}
@Nested
class TestQuery {
@Test
void shouldHavePaging() {
var request = SearchRequestTestFactory.create();
var query = searchRepostitory.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getPageable()).isNotNull();
assertThat(query.getPageable().getOffset()).isZero();
assertThat(query.getPageable().getPageSize()).isEqualTo(SearchRequestTestFactory.LIMIT);
assertThat(query.getPageable().getSort()).isEqualTo(Sort.unsorted());
}
@Test
void shouldHaveQuery() {
var request = SearchRequestTestFactory.create();
var query = searchRepostitory.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getQuery()).isNotNull();
assertThat(query.getQuery()).asString().contains("\"query\" : \"*vors*\"");
assertThat(query.getQuery()).asString().contains("aktenzeichen^2.0");
assertThat(query.getQuery()).asString().contains("antragstellerName^1.0");
assertThat(query.getQuery()).asString().contains("antragstellerVorname^1.0");
assertThat(query.getQuery()).asString().contains("vorgangName^0.5");
assertThat(query.getQuery()).asString().contains("vorgangNummer^2.0");
}
@Nested
class forRolePoststelle {
@Test
void shouldHaveStatusFilterOnly() {
var request = SearchRequestTestFactory.createBuilder().filterByOrganisationseinheitIds(false).organisationseinheitIds(null)
.status(List.of(Status.ABGESCHLOSSEN.name()))
.build();
var query = searchRepostitory.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getFilter()).isNotNull();
assertThat(query.getFilter()).asString().contains("status");
assertThat(query.getFilter()).asString().contains(Status.ABGESCHLOSSEN.name());
assertThat(query.getFilter()).asString().doesNotContain("organisationseinheitenId");
}
@Test
void shouldHaveOrganisationseinheitenIdFilterOnly() {
var request = SearchRequestTestFactory.create();
var query = searchRepostitory.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getFilter()).isNotNull();
assertThat(query.getFilter()).asString().contains("organisationseinheitenId");
assertThat(query.getFilter()).asString().contains(SearchRequestTestFactory.ORGANISATIONSEINHEIT_ID);
}
@Test
void shouldHaveOrganisationseinheitenAndStatusFilter() {
var request = SearchRequestTestFactory.createBuilder().status(List.of(Status.ABGESCHLOSSEN.name())).build();
var query = searchRepostitory.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getFilter()).isNotNull();
assertThat(query.getFilter()).asString().contains("organisationseinheitenId");
assertThat(query.getFilter()).asString().contains(SearchRequestTestFactory.ORGANISATIONSEINHEIT_ID);
assertThat(query.getFilter()).asString().contains("status");
assertThat(query.getFilter()).asString().contains(Status.ABGESCHLOSSEN.name());
}
}
@Nested
class forOtherRoles {
@Test
void shouldHaveOrganisationseinheitenIdFilter() {
var request = SearchRequestTestFactory.create();
var query = searchRepostitory.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getFilter()).isNotNull();
assertThat(query.getFilter()).asString().contains("organisationseinheitenId");
assertThat(query.getFilter()).asString().contains(SearchRequestTestFactory.ORGANISATIONSEINHEIT_ID);
}
@Test
void shouldHaveAssignedToFilter() {
var request = SearchRequestTestFactory.create();
var query = searchRepostitory.createQuery(request, PageRequest.of(request.getOffSet(), request.getLimit()));
assertThat(query.getFilter()).isNotNull();
assertThat(query.getFilter()).asString().contains("assignedTo");
assertThat(query.getFilter()).asString().contains(SearchRequestTestFactory.ASSIGNED_TO);
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment