From 5f66e958d4bebe7e2217cd1f33e2becf6b1ab2e1 Mon Sep 17 00:00:00 2001 From: Aleksei Pronichev Date: Tue, 18 Jun 2024 13:25:29 +0500 Subject: [PATCH] [MSEARCH-784] add bibframe authority index --- descriptors/ModuleDescriptor-template.json | 9 +++ .../search/controller/SearchController.java | 19 ++++++ .../integration/KafkaMessageListener.java | 17 +++++ .../BibframeAuthorityLabelProcessor.java | 14 ++++ .../BibframeAuthorityLccnProcessor.java | 39 +++++++++++ .../BibframeAuthorityTypeProcessor.java | 18 +++++ .../folio/search/utils/KafkaConstants.java | 1 + .../org/folio/search/utils/SearchUtils.java | 1 + src/main/resources/application.yml | 4 ++ .../index/bibframe-authority.json | 68 +++++++++++++++++++ .../resources/model/bibframe_authority.json | 45 ++++++++++++ .../result/bibframeSearchAuthorityResult.yaml | 12 ++++ .../resources/swagger.api/mod-search.yaml | 3 + .../search-bibframe-authorities.yaml | 25 +++++++ .../dto/bibframe/bibframeAuthority.yaml | 25 +++++++ .../bibframeSearchAuthorityResult.yaml | 20 ++++++ .../controller/SearchBibframeAuthorityIT.java | 54 +++++++++++++++ .../folio/search/sample/SampleBibframe.java | 14 ++++ .../search/support/base/ApiEndpoints.java | 4 ++ .../support/base/BaseIntegrationTest.java | 13 ++++ .../org/folio/search/utils/TestConstants.java | 5 ++ src/test/resources/application.yml | 7 ++ .../samples/bibframe/authority_concept.json | 15 ++++ .../samples/bibframe/authority_person.json | 11 +++ 24 files changed, 443 insertions(+) create mode 100644 src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLabelProcessor.java create mode 100644 src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLccnProcessor.java create mode 100644 src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityTypeProcessor.java create mode 100644 src/main/resources/elasticsearch/index/bibframe-authority.json create mode 100644 src/main/resources/model/bibframe_authority.json create mode 100644 src/main/resources/swagger.api/examples/result/bibframeSearchAuthorityResult.yaml create mode 100644 src/main/resources/swagger.api/paths/search-bibframe/search-bibframe-authorities.yaml create mode 100644 src/main/resources/swagger.api/schemas/dto/bibframe/bibframeAuthority.yaml create mode 100644 src/main/resources/swagger.api/schemas/response/bibframeSearchAuthorityResult.yaml create mode 100644 src/test/java/org/folio/search/controller/SearchBibframeAuthorityIT.java create mode 100644 src/test/resources/samples/bibframe/authority_concept.json create mode 100644 src/test/resources/samples/bibframe/authority_person.json diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index e741c054a..f4909dafa 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -111,6 +111,15 @@ "search.bibframe.collection.get" ] }, + { + "methods": [ + "GET" + ], + "pathPattern": "/search/bibframe/authorities", + "permissionsRequired": [ + "search.bibframe.collection.get" + ] + }, { "methods": [ "GET" diff --git a/src/main/java/org/folio/search/controller/SearchController.java b/src/main/java/org/folio/search/controller/SearchController.java index 7813c6165..a8c9b8ac2 100644 --- a/src/main/java/org/folio/search/controller/SearchController.java +++ b/src/main/java/org/folio/search/controller/SearchController.java @@ -4,6 +4,8 @@ import org.folio.search.domain.dto.Authority; import org.folio.search.domain.dto.AuthoritySearchResult; import org.folio.search.domain.dto.Bibframe; +import org.folio.search.domain.dto.BibframeAuthority; +import org.folio.search.domain.dto.BibframeSearchAuthorityResult; import org.folio.search.domain.dto.BibframeSearchResult; import org.folio.search.domain.dto.Instance; import org.folio.search.domain.dto.InstanceSearchResult; @@ -65,6 +67,23 @@ public ResponseEntity searchBibframe(String tenant, String ); } + @Override + public ResponseEntity searchBibframeAuthorities(String tenant, + String query, + Integer limit, + Integer offset) { + var searchRequest = CqlSearchRequest.of( + BibframeAuthority.class, tenant, query, limit, offset, true); + var result = searchService.search(searchRequest); + return ResponseEntity.ok(new BibframeSearchAuthorityResult() + .searchQuery(query) + .content(result.getRecords()) + .pageNumber(divPlusOneIfRemainder(offset, limit)) + .totalPages(divPlusOneIfRemainder(result.getTotalRecords(), limit)) + .totalRecords(result.getTotalRecords()) + ); + } + private int divPlusOneIfRemainder(int one, int two) { var modulo = one % two; return one / two + (modulo > 0 ? 1 : 0); diff --git a/src/main/java/org/folio/search/integration/KafkaMessageListener.java b/src/main/java/org/folio/search/integration/KafkaMessageListener.java index f580bdd84..61d8c1f61 100644 --- a/src/main/java/org/folio/search/integration/KafkaMessageListener.java +++ b/src/main/java/org/folio/search/integration/KafkaMessageListener.java @@ -10,6 +10,7 @@ import static org.folio.search.utils.SearchConverterUtils.getEventPayload; import static org.folio.search.utils.SearchConverterUtils.getResourceEventId; import static org.folio.search.utils.SearchConverterUtils.getResourceSource; +import static org.folio.search.utils.SearchUtils.BIBFRAME_AUTHORITY_RESOURCE; import static org.folio.search.utils.SearchUtils.BIBFRAME_RESOURCE; import static org.folio.search.utils.SearchUtils.ID_FIELD; import static org.folio.search.utils.SearchUtils.INSTANCE_ID_FIELD; @@ -212,6 +213,22 @@ public void handleBibframeEvents(List> con indexResources(batch, resourceService::indexResources); } + @KafkaListener( + id = KafkaConstants.BIBFRAME_AUTHORITY_LISTENER_ID, + containerFactory = "standardListenerContainerFactory", + groupId = "#{folioKafkaProperties.listener['bibframe-authorities'].groupId}", + concurrency = "#{folioKafkaProperties.listener['bibframe-authorities'].concurrency}", + topicPattern = "#{folioKafkaProperties.listener['bibframe-authorities'].topicPattern}") + public void handleBibframeAuthorityEvents(List> consumerRecords) { + log.info("Processing bibframe events from Kafka [number of events: {}]", consumerRecords.size()); + var batch = consumerRecords.stream() + .map(ConsumerRecord::value) + .map(bibAuthority -> bibAuthority.resourceName(BIBFRAME_AUTHORITY_RESOURCE).id(getResourceEventId(bibAuthority))) + .toList(); + + indexResources(batch, resourceService::indexResources); + } + private void indexResources(List batch, Consumer> indexConsumer) { var batchByTenant = batch.stream().collect(Collectors.groupingBy(ResourceEvent::getTenant)); diff --git a/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLabelProcessor.java b/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLabelProcessor.java new file mode 100644 index 000000000..ab8d90e96 --- /dev/null +++ b/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLabelProcessor.java @@ -0,0 +1,14 @@ +package org.folio.search.service.setter.bibframe.authority; + +import org.folio.search.domain.dto.BibframeAuthority; +import org.folio.search.service.setter.FieldProcessor; +import org.springframework.stereotype.Component; + +@Component +public class BibframeAuthorityLabelProcessor implements FieldProcessor { + + @Override + public String getFieldValue(BibframeAuthority bibframe) { + return bibframe.getLabel(); + } +} diff --git a/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLccnProcessor.java b/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLccnProcessor.java new file mode 100644 index 000000000..4c72f3e9f --- /dev/null +++ b/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityLccnProcessor.java @@ -0,0 +1,39 @@ +package org.folio.search.service.setter.bibframe.authority; + +import static java.util.stream.Collectors.toCollection; +import static org.folio.search.domain.dto.BibframeAuthorityIdentifiersInner.TypeEnum.LCCN; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.folio.search.domain.dto.BibframeAuthority; +import org.folio.search.domain.dto.BibframeAuthorityIdentifiersInner; +import org.folio.search.service.lccn.LccnNormalizer; +import org.folio.search.service.setter.FieldProcessor; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class BibframeAuthorityLccnProcessor implements FieldProcessor> { + + @Qualifier("lccnNormalizerStructureB") + private final LccnNormalizer lccnNormalizer; + + @Override + public Set getFieldValue(BibframeAuthority bibframe) { + return Optional.of(bibframe) + .map(BibframeAuthority::getIdentifiers) + .orElseGet(Collections::emptyList) + .stream() + .filter(i -> LCCN.equals(i.getType())) + .map(BibframeAuthorityIdentifiersInner::getValue) + .filter(Objects::nonNull) + .map(lccnNormalizer) + .flatMap(Optional::stream) + .collect(toCollection(LinkedHashSet::new)); + } +} diff --git a/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityTypeProcessor.java b/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityTypeProcessor.java new file mode 100644 index 000000000..70b3fb375 --- /dev/null +++ b/src/main/java/org/folio/search/service/setter/bibframe/authority/BibframeAuthorityTypeProcessor.java @@ -0,0 +1,18 @@ +package org.folio.search.service.setter.bibframe.authority; + +import org.folio.search.domain.dto.BibframeAuthority; +import org.folio.search.service.setter.FieldProcessor; +import org.springframework.stereotype.Component; + +@Component +public class BibframeAuthorityTypeProcessor implements FieldProcessor { + + @Override + public String getFieldValue(BibframeAuthority bibframe) { + var type = bibframe.getType(); + if (type == null) { + return null; + } + return type.toString(); + } +} diff --git a/src/main/java/org/folio/search/utils/KafkaConstants.java b/src/main/java/org/folio/search/utils/KafkaConstants.java index d192c4245..38ec41432 100644 --- a/src/main/java/org/folio/search/utils/KafkaConstants.java +++ b/src/main/java/org/folio/search/utils/KafkaConstants.java @@ -9,6 +9,7 @@ public final class KafkaConstants { public static final String CLASSIFICATION_TYPE_LISTENER_ID = "mod-search-classification-type-listener"; public static final String LOCATION_LISTENER_ID = "mod-search-location-listener"; public static final String BIBFRAME_LISTENER_ID = "mod-search-bibframe-listener"; + public static final String BIBFRAME_AUTHORITY_LISTENER_ID = "mod-search-bibframe-authorities-listener"; private KafkaConstants() {} } diff --git a/src/main/java/org/folio/search/utils/SearchUtils.java b/src/main/java/org/folio/search/utils/SearchUtils.java index 5e4439f36..e813b10a2 100644 --- a/src/main/java/org/folio/search/utils/SearchUtils.java +++ b/src/main/java/org/folio/search/utils/SearchUtils.java @@ -39,6 +39,7 @@ public class SearchUtils { public static final String LOCATION_RESOURCE = "location"; public static final String CLASSIFICATION_TYPE_RESOURCE = "classification-type"; public static final String BIBFRAME_RESOURCE = "bibframe"; + public static final String BIBFRAME_AUTHORITY_RESOURCE = "bibframe-authority"; public static final String ID_FIELD = "id"; public static final String SOURCE_FIELD = "source"; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 969013fc7..a523fa0de 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -139,6 +139,10 @@ folio: concurrency: ${KAFKA_BIBFRAME_CONCURRENCY:1} topic-pattern: (${folio.environment}\.)(.*\.)search\.bibframe group-id: ${folio.environment}-mod-search-bibframe-group + bibframe-authorities: + concurrency: ${KAFKA_BIBFRAME_CONCURRENCY:1} + topic-pattern: (${folio.environment}\.)(.*\.)search\.bibframe-authorities + group-id: ${folio.environment}-mod-search-bibframe-authorities-group okapiUrl: ${okapi.url} logging: request: diff --git a/src/main/resources/elasticsearch/index/bibframe-authority.json b/src/main/resources/elasticsearch/index/bibframe-authority.json new file mode 100644 index 000000000..137a49b25 --- /dev/null +++ b/src/main/resources/elasticsearch/index/bibframe-authority.json @@ -0,0 +1,68 @@ +{ + "index": { + "number_of_shards": 4, + "number_of_replicas": 2, + "refresh_interval": "1s", + "codec": "best_compression", + "mapping.total_fields.limit": 1000 + }, + "analysis": { + "filter": { + "folio_word_delimiter_graph": { + "type": "word_delimiter_graph", + "catenate_words": true + } + }, + "normalizer": { + "keyword_lowercase": { + "filter": [ + "lowercase", + "trim" + ], + "type": "custom" + }, + "keyword_uppercase": { + "filter": [ + "uppercase", + "trim" + ], + "type": "custom" + }, + "keyword_trimmed": { + "filter": [ + "trim" + ], + "type": "custom" + } + }, + "analyzer": { + "source_analyzer": { + "tokenizer": "icu_tokenizer", + "filter": [ + "folio_word_delimiter_graph", + "icu_folding" + ], + "char_filter": [ + "and_char_replacement" + ], + "type": "custom" + }, + "whitespace_lowercase_analyzer": { + "tokenizer": "whitespace", + "filter": [ + "lowercase", + "icu_folding" + ], + "type": "custom" + } + }, + "tokenizers": { }, + "char_filter": { + "and_char_replacement": { + "type": "pattern_replace", + "pattern": " & ", + "replacement": " and " + } + } + } +} diff --git a/src/main/resources/model/bibframe_authority.json b/src/main/resources/model/bibframe_authority.json new file mode 100644 index 000000000..8795ad603 --- /dev/null +++ b/src/main/resources/model/bibframe_authority.json @@ -0,0 +1,45 @@ +{ + "name": "bibframe-authority", + "eventBodyJavaClass": "org.folio.search.domain.dto.BibframeAuthority", + "languageSourcePaths": ["$.languages"], + "fields": { + "id": { + "index": "keyword" + }, + "label": { + "index": "whitespace" + }, + "type": { + "index": "keyword" + }, + "identifiers": { + "type": "object", + "properties": { + "value": { + "index": "whitespace" + }, + "type": { + "index": "whitespace" + } + } + } + }, + "searchFields": { + "label": { + "type": "search", + "index": "multilang", + "processor": "bibframeAuthorityLabelProcessor" + }, + "type": { + "type": "search", + "index": "keyword", + "processor": "bibframeAuthorityTypeProcessor" + }, + "lccn": { + "type": "search", + "index": "keyword", + "processor": "bibframeAuthorityLccnProcessor" + } + }, + "indexMappings": { } +} diff --git a/src/main/resources/swagger.api/examples/result/bibframeSearchAuthorityResult.yaml b/src/main/resources/swagger.api/examples/result/bibframeSearchAuthorityResult.yaml new file mode 100644 index 000000000..a35956d7b --- /dev/null +++ b/src/main/resources/swagger.api/examples/result/bibframeSearchAuthorityResult.yaml @@ -0,0 +1,12 @@ +value: + searchQuery: "query string" + content: + - id: "1" + label: "Label Value" + type: "Person" + identifiers: + - value: "sh85121033" + type: "LCCN" + pageNumber: 0 + totalPages: 3 + totalRecords: 27 diff --git a/src/main/resources/swagger.api/mod-search.yaml b/src/main/resources/swagger.api/mod-search.yaml index 71390f7e3..85d1a2267 100644 --- a/src/main/resources/swagger.api/mod-search.yaml +++ b/src/main/resources/swagger.api/mod-search.yaml @@ -118,6 +118,9 @@ paths: /search/bibframe: $ref: 'paths/search-bibframe/search-bibframe.yaml' + /search/bibframe/authorities: + $ref: 'paths/search-bibframe/search-bibframe-authorities.yaml' + /browse/call-numbers/instances: $ref: 'paths/browse-call-numbers/browse-call-numbers-instances.yaml' diff --git a/src/main/resources/swagger.api/paths/search-bibframe/search-bibframe-authorities.yaml b/src/main/resources/swagger.api/paths/search-bibframe/search-bibframe-authorities.yaml new file mode 100644 index 000000000..3035a98b6 --- /dev/null +++ b/src/main/resources/swagger.api/paths/search-bibframe/search-bibframe-authorities.yaml @@ -0,0 +1,25 @@ +get: + operationId: searchBibframeAuthorities + summary: Search Bibframe Authorities + description: Get a list of bibframe authorities records for CQL query + tags: + - search + parameters: + - $ref: '../../parameters/x-okapi-tenant-header.yaml' + - $ref: '../../parameters/cql-query.yaml' + - $ref: '../../parameters/bibframe-limit-param.yaml' + - $ref: '../../parameters/offset-param.yaml' + responses: + '200': + description: 'Bibframe authorities search result' + content: + application/json: + schema: + $ref: '../../schemas/response/bibframeSearchAuthorityResult.yaml' + examples: + searchResult: + $ref: '../../examples/result/bibframeSearchAuthorityResult.yaml' + '400': + $ref: '../../responses/badRequestResponse.yaml' + '500': + $ref: '../../responses/internalServerErrorResponse.yaml' diff --git a/src/main/resources/swagger.api/schemas/dto/bibframe/bibframeAuthority.yaml b/src/main/resources/swagger.api/schemas/dto/bibframe/bibframeAuthority.yaml new file mode 100644 index 000000000..cb170b9cd --- /dev/null +++ b/src/main/resources/swagger.api/schemas/dto/bibframe/bibframeAuthority.yaml @@ -0,0 +1,25 @@ +description: "Bibframe authority search dto, contains Authority adn Identifiers" +type: "object" +properties: + id: + description: "The Linked Data ID of an Authority" + type: "string" + label: + description: "Value of Label" + type: "string" + type: + type: "string" + identifiers: + type: "array" + description: "Authority identifier array" + items: + properties: + value: + type: "string" + description: "Value of Identifier" + type: + type: "string" + enum: + - "LCCN" +required: + - "id" diff --git a/src/main/resources/swagger.api/schemas/response/bibframeSearchAuthorityResult.yaml b/src/main/resources/swagger.api/schemas/response/bibframeSearchAuthorityResult.yaml new file mode 100644 index 000000000..dbb62830d --- /dev/null +++ b/src/main/resources/swagger.api/schemas/response/bibframeSearchAuthorityResult.yaml @@ -0,0 +1,20 @@ +description: "Bibframe authority search result response" +type: "object" +properties: + searchQuery: + type: "string" + description: "Initial search query" + content: + type: "array" + description: "List of bibframe authority records found" + items: + $ref: "../../schemas/dto/bibframe/bibframeAuthority.yaml" + pageNumber: + type: "integer" + description: "Current results page number, 0 by default" + totalPages: + type: "integer" + description: "Total pages count" + totalRecords: + type: "integer" + description: "Total results count" diff --git a/src/test/java/org/folio/search/controller/SearchBibframeAuthorityIT.java b/src/test/java/org/folio/search/controller/SearchBibframeAuthorityIT.java new file mode 100644 index 000000000..207aa6261 --- /dev/null +++ b/src/test/java/org/folio/search/controller/SearchBibframeAuthorityIT.java @@ -0,0 +1,54 @@ +package org.folio.search.controller; + +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; + +import org.folio.search.domain.dto.BibframeAuthority; +import org.folio.search.sample.SampleBibframe; +import org.folio.search.support.base.BaseIntegrationTest; +import org.folio.spring.testing.type.IntegrationTest; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +@IntegrationTest +class SearchBibframeAuthorityIT extends BaseIntegrationTest { + + @BeforeAll + static void prepare() { + setUpTenant(BibframeAuthority.class, 2, + SampleBibframe.getBibframeAuthorityConceptSampleAsMap(), SampleBibframe.getBibframeAuthorityPersonSampleAsMap() + ); + } + + @AfterAll + static void cleanUp() { + removeTenant(); + } + + @DisplayName("search by authority bibframe (all authorities are found)") + @ParameterizedTest(name = "[{0}] {2}") + @CsvSource({ + " 1, 2, label any \"*\"", + " 2, 2, label any \"*-*\"", + " 3, 2, label any \"*-label\"", + " 4, 2, label <> \"lab\"", + " 5, 1, label any \"concept-*\"", + " 6, 1, label = \"concept-label\"", + " 7, 1, label any \"person-*\"", + " 8, 1, label = \"person-label\"", + " 9, 1, type = \"PERSON\"", + "10, 1, type = \"CONCEPT\"", + "11, 2, lccn <> \"2024\"", + "12, 1, lccn = \"2024101103\"", + "13, 2, lccn = \"2024202454\"", + "14, 1, lccn = \"2024202454\" AND type = \"PERSON\"", + "15, 1, lccn = \"2024202454\" AND type = \"CONCEPT\"", + }) + void searchByBibframe_parameterized_singleResult(int index, int size, String query) throws Throwable { + doSearchByBibframeAuthority(query) + .andExpect(jsonPath("$.totalRecords", is(size))); + } +} diff --git a/src/test/java/org/folio/search/sample/SampleBibframe.java b/src/test/java/org/folio/search/sample/SampleBibframe.java index 56962f4d0..0fc0355b6 100644 --- a/src/test/java/org/folio/search/sample/SampleBibframe.java +++ b/src/test/java/org/folio/search/sample/SampleBibframe.java @@ -16,6 +16,12 @@ public class SampleBibframe { private static final Map BIBFRAME_2_AS_MAP = readJsonFromFile("/samples/bibframe/bibframe2.json", MAP_TYPE_REFERENCE); + private static final Map BIBFRAME_AUTHORITY_CONCEPT_AS_MAP = + readJsonFromFile("/samples/bibframe/authority_concept.json", MAP_TYPE_REFERENCE); + + private static final Map BIBFRAME_AUTHORITY_PERSON_AS_MAP = + readJsonFromFile("/samples/bibframe/authority_person.json", MAP_TYPE_REFERENCE); + public static Map getBibframeSampleAsMap() { return BIBFRAME_AS_MAP; } @@ -23,4 +29,12 @@ public static Map getBibframeSampleAsMap() { public static Map getBibframe2SampleAsMap() { return BIBFRAME_2_AS_MAP; } + + public static Map getBibframeAuthorityConceptSampleAsMap() { + return BIBFRAME_AUTHORITY_CONCEPT_AS_MAP; + } + + public static Map getBibframeAuthorityPersonSampleAsMap() { + return BIBFRAME_AUTHORITY_PERSON_AS_MAP; + } } diff --git a/src/test/java/org/folio/search/support/base/ApiEndpoints.java b/src/test/java/org/folio/search/support/base/ApiEndpoints.java index 5f8c14f3d..b3fe38d00 100644 --- a/src/test/java/org/folio/search/support/base/ApiEndpoints.java +++ b/src/test/java/org/folio/search/support/base/ApiEndpoints.java @@ -81,6 +81,10 @@ public static String bibframeSearchPath() { return "/search/bibframe"; } + public static String bibframeAuthoritySearchPath() { + return "/search/bibframe/authorities"; + } + public static String authorityBrowsePath() { return "/browse/authorities"; } diff --git a/src/test/java/org/folio/search/support/base/BaseIntegrationTest.java b/src/test/java/org/folio/search/support/base/BaseIntegrationTest.java index 96c644e06..5059a9888 100644 --- a/src/test/java/org/folio/search/support/base/BaseIntegrationTest.java +++ b/src/test/java/org/folio/search/support/base/BaseIntegrationTest.java @@ -5,10 +5,12 @@ import static org.awaitility.Durations.TWO_HUNDRED_MILLISECONDS; import static org.awaitility.Durations.TWO_MINUTES; import static org.folio.search.support.base.ApiEndpoints.authoritySearchPath; +import static org.folio.search.support.base.ApiEndpoints.bibframeAuthoritySearchPath; import static org.folio.search.support.base.ApiEndpoints.bibframeSearchPath; import static org.folio.search.support.base.ApiEndpoints.instanceSearchPath; import static org.folio.search.utils.SearchUtils.getIndexName; import static org.folio.search.utils.TestConstants.TENANT_ID; +import static org.folio.search.utils.TestConstants.bibframeAuthorityTopic; import static org.folio.search.utils.TestConstants.bibframeTopic; import static org.folio.search.utils.TestConstants.inventoryAuthorityTopic; import static org.folio.search.utils.TestUtils.asJsonString; @@ -40,6 +42,7 @@ import lombok.extern.log4j.Log4j2; import org.folio.search.domain.dto.Authority; import org.folio.search.domain.dto.Bibframe; +import org.folio.search.domain.dto.BibframeAuthority; import org.folio.search.domain.dto.FeatureConfig; import org.folio.search.domain.dto.Instance; import org.folio.search.domain.dto.ResourceEvent; @@ -164,6 +167,11 @@ protected static ResultActions doSearchByBibframe(String query) { return doSearch(bibframeSearchPath(), TENANT_ID, query, null, null, null); } + @SneakyThrows + protected static ResultActions doSearchByBibframeAuthority(String query) { + return doSearch(bibframeAuthoritySearchPath(), TENANT_ID, query, null, null, null); + } + @SneakyThrows protected static ResultActions attemptSearchByAuthorities(String query) { return attemptSearch(authoritySearchPath(), TENANT_ID, query, null, null, null); @@ -290,6 +298,11 @@ protected static void setUpTenant(Class type, String tenant, Runnable postIni setUpTenant(tenant, bibframeSearchPath(), postInitAction, asList(records), expectedCount, bibframe -> kafkaTemplate.send(bibframeTopic(tenant), resourceEvent(null, null, bibframe))); } + + if (type.equals(BibframeAuthority.class)) { + setUpTenant(tenant, bibframeAuthoritySearchPath(), postInitAction, asList(records), expectedCount, + bibAuth -> kafkaTemplate.send(bibframeAuthorityTopic(tenant), resourceEvent(null, null, bibAuth))); + } } @SneakyThrows diff --git a/src/test/java/org/folio/search/utils/TestConstants.java b/src/test/java/org/folio/search/utils/TestConstants.java index d9805e3d4..f8562fd51 100644 --- a/src/test/java/org/folio/search/utils/TestConstants.java +++ b/src/test/java/org/folio/search/utils/TestConstants.java @@ -38,6 +38,7 @@ public class TestConstants { public static final String INVENTORY_CLASSIFICATION_TYPE_TOPIC = "inventory.classification-type"; public static final String CONSORTIUM_INSTANCE_TOPIC = "search.consortium.instance"; public static final String BIBFRAME_TOPIC = "search.bibframe"; + public static final String BIBFRAME_AUTHORITY_TOPIC = "search.bibframe-authorities"; public static final String LOCAL_CN_TYPE = "6fd29f52-5c9c-44d0-b529-e9c5eb3a0aba"; public static final String FOLIO_CN_TYPE = "6e4d7565-b277-4dfa-8b7d-fbf306d9d0cd"; @@ -124,6 +125,10 @@ public static String bibframeTopic(String tenantId) { return getTopicName(tenantId, BIBFRAME_TOPIC); } + public static String bibframeAuthorityTopic(String tenantId) { + return getTopicName(tenantId, BIBFRAME_AUTHORITY_TOPIC); + } + public static String indexName(String tenantId) { return String.join("_", ENV, INSTANCE_RESOURCE, tenantId); } diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 939849430..b93d06784 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -113,6 +113,9 @@ folio: - name: search.bibframe numPartitions: 1 replicationFactor: 1 + - name: search.bibframe-authorities + numPartitions: 1 + replicationFactor: 1 listener: events: concurrency: 2 @@ -146,6 +149,10 @@ folio: concurrency: ${KAFKA_BIBFRAME_CONCURRENCY:1} topic-pattern: ${KAFKA_BIBFRAME_CONSUMER_PATTERN:(${folio.environment}\.)(.*\.)search\.bibframe} group-id: ${folio.environment}-mod-search-bibframe-group + bibframe-authorities: + concurrency: ${KAFKA_BIBFRAME_CONCURRENCY:1} + topic-pattern: (${folio.environment}\.)(.*\.)search\.bibframe-authorities + group-id: ${folio.environment}-mod-search-bibframe-authorities-group okapiUrl: ${okapi.url} logging: request: diff --git a/src/test/resources/samples/bibframe/authority_concept.json b/src/test/resources/samples/bibframe/authority_concept.json new file mode 100644 index 000000000..a5b165014 --- /dev/null +++ b/src/test/resources/samples/bibframe/authority_concept.json @@ -0,0 +1,15 @@ +{ + "id": "123456654321", + "label": "concept-label", + "type": "CONCEPT", + "identifiers": [ + { + "value": "2024-202454/AC/r967", + "type": "LCCN" + }, + { + "value": "2024-101103/AC/a008", + "type": "LCCN" + } + ] +} diff --git a/src/test/resources/samples/bibframe/authority_person.json b/src/test/resources/samples/bibframe/authority_person.json new file mode 100644 index 000000000..c02ce04a5 --- /dev/null +++ b/src/test/resources/samples/bibframe/authority_person.json @@ -0,0 +1,11 @@ +{ + "id": "123456654322", + "label": "person-label", + "type": "PERSON", + "identifiers": [ + { + "value": "2024-202454/PR/r006", + "type": "LCCN" + } + ] +}