diff --git a/NEWS.md b/NEWS.md index 9a3192e32..7353513ea 100644 --- a/NEWS.md +++ b/NEWS.md @@ -40,6 +40,7 @@ * Create computed field for sorting and filtering Date 1 ([MSEARCH-806](https://folio-org.atlassian.net/browse/MSEARCH-806)) * Support filters for subject source and type on subject browse ([MSEARCH-805](https://folio-org.atlassian.net/browse/MSEARCH-805)) * Implement new re-index flow for instance records ([MSEARCH-793](https://folio-org.atlassian.net/issues/MSEARCH-793), [MSEARCH-794](https://folio-org.atlassian.net/issues/MSEARCH-794), [MSEARCH-796](https://folio-org.atlassian.net/issues/MSEARCH-796), [MSEARCH-797](https://folio-org.atlassian.net/issues/MSEARCH-797), [MSEARCH-798](https://folio-org.atlassian.net/issues/MSEARCH-798), [MSEARCH-799](https://folio-org.atlassian.net/issues/MSEARCH-799), [MSEARCH-800](https://folio-org.atlassian.net/issues/MSEARCH-800), [MSEARCH-801](https://folio-org.atlassian.net/issues/MSEARCH-801), [MSEARCH-802](https://folio-org.atlassian.net/issues/MSEARCH-802)) +* Implement Linked Data HUB index and search API ([MSEARCH-844](https://folio-org.atlassian.net/browse/MSEARCH-844)) ### Bug fixes * Do not delete kafka topics if collection topic is enabled ([MSEARCH-725](https://folio-org.atlassian.net/browse/MSEARCH-725)) diff --git a/README.md b/README.md index b17c09766..b4bafb5e1 100644 --- a/README.md +++ b/README.md @@ -328,11 +328,11 @@ x-okapi-token: [JWT_TOKEN] ``` * `resourceName` parameter is optional and equal to `instance` by default. Possible values: `instance`, `authority`, `location`, - `linked-data-instance`, `linked-data-work`, `linked-data-authority`. Please note that `location` reindex is synchronous. + `linked-data-instance`, `linked-data-work`, `linked-data-hub`. Please note that `location` reindex is synchronous. * `recreateIndex` parameter is optional and equal to `false` by default. If it is equal to `true` then mod-search will drop existing indices for tenant and resource, creating them again. Executing request with this parameter equal to `true` in query will erase all the tenant data in mod-search. -* Please note that for `linked-data-instance`, `linked-data-work` and `linked-data-authority` resources the endpoint is used only for index recreation +* Please note that for `linked-data-instance`, `linked-data-work` and `linked-data-hub` resources the endpoint is used only for index recreation purpose and actual reindex operation is triggered through mod-linked-data. ### Monitoring reindex process @@ -518,16 +518,16 @@ Consortium feature on module enable is defined by 'centralTenantId' tenant param ### Search API -| METHOD | URL | DESCRIPTION | -|:-------|:----------------------------------|:-------------------------------------------------------------------------------------| -| GET | `/search/instances` | Search by instances and to this instance items and holding-records | -| GET | `/search/authorities` | Search by authority records | -| GET | `/search/linked-data/instances` | Search linked data graph instance resource descriptions | -| GET | `/search/linked-data/works` | Search linked data graph work resource descriptions | -| GET | `/search/linked-data/authorities` | Search linked data graph authority resource descriptions | -| GET | `/search/{recordType}/facets` | Get facets where recordType could be: instances, authorities, contributors, subjects | -| GET | ~~`/search/instances/ids`~~ | (DEPRECATED) Stream instance ids as JSON or plain text | -| GET | ~~`/search/holdings/ids`~~ | (DEPRECATED) Stream holding record ids as JSON or plain text | +| METHOD | URL | DESCRIPTION | +|:-------|:--------------------------------|:-------------------------------------------------------------------------------------| +| GET | `/search/instances` | Search by instances and to this instance items and holding-records | +| GET | `/search/authorities` | Search by authority records | +| GET | `/search/linked-data/instances` | Search linked data graph instance resource descriptions | +| GET | `/search/linked-data/works` | Search linked data graph work resource descriptions | +| GET | `/search/linked-data/hubs` | Search linked data graph hub resource descriptions | +| GET | `/search/{recordType}/facets` | Get facets where recordType could be: instances, authorities, contributors, subjects | +| GET | ~~`/search/instances/ids`~~ | (DEPRECATED) Stream instance ids as JSON or plain text | +| GET | ~~`/search/holdings/ids`~~ | (DEPRECATED) Stream holding record ids as JSON or plain text | #### Searching and filtering diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index e2221ed53..8323ac283 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -170,9 +170,9 @@ "methods": [ "GET" ], - "pathPattern": "/search/linked-data/authorities", + "pathPattern": "/search/linked-data/hubs", "permissionsRequired": [ - "search.linked-data.authority.collection.get" + "search.linked-data.hub.collection.get" ], "modulePermissions": [ "user-tenants.collection.get" @@ -717,9 +717,9 @@ "description": "Searches linked data works by given query" }, { - "permissionName": "search.linked-data.authority.collection.get", - "displayName": "Search - searches linked data authorities by given query", - "description": "Searches linked data authorities by given query" + "permissionName": "search.linked-data.hub.collection.get", + "displayName": "Search - searches linked data hubs by given query", + "description": "Searches linked data hubs by given query" }, { "permissionName": "browse.call-numbers.instances.collection.get", diff --git a/src/main/java/org/folio/search/controller/SearchController.java b/src/main/java/org/folio/search/controller/SearchController.java index d80c37250..50a95aafb 100644 --- a/src/main/java/org/folio/search/controller/SearchController.java +++ b/src/main/java/org/folio/search/controller/SearchController.java @@ -7,8 +7,8 @@ import org.folio.search.domain.dto.AuthoritySearchResult; import org.folio.search.domain.dto.Instance; import org.folio.search.domain.dto.InstanceSearchResult; -import org.folio.search.domain.dto.LinkedDataAuthority; -import org.folio.search.domain.dto.LinkedDataAuthoritySearchResult; +import org.folio.search.domain.dto.LinkedDataHub; +import org.folio.search.domain.dto.LinkedDataHubSearchResult; import org.folio.search.domain.dto.LinkedDataInstance; import org.folio.search.domain.dto.LinkedDataInstanceSearchResult; import org.folio.search.domain.dto.LinkedDataWork; @@ -93,14 +93,14 @@ public ResponseEntity searchLinkedDataWorks(String t } @Override - public ResponseEntity searchLinkedDataAuthorities(String tenantId, - String query, - Integer limit, - Integer offset) { + public ResponseEntity searchLinkedDataHubs(String tenantId, + String query, + Integer limit, + Integer offset) { var searchRequest = CqlSearchRequest.of( - LinkedDataAuthority.class, tenantId, query, limit, offset, true); + LinkedDataHub.class, tenantId, query, limit, offset, true); var result = searchService.search(searchRequest); - return ResponseEntity.ok(new LinkedDataAuthoritySearchResult() + return ResponseEntity.ok(new LinkedDataHubSearchResult() .searchQuery(query) .content(result.getRecords()) .pageNumber(divPlusOneIfRemainder(offset, limit)) diff --git a/src/main/java/org/folio/search/integration/message/interceptor/ResourceEventBatchInterceptor.java b/src/main/java/org/folio/search/integration/message/interceptor/ResourceEventBatchInterceptor.java index e07dc6e6f..3f69275af 100644 --- a/src/main/java/org/folio/search/integration/message/interceptor/ResourceEventBatchInterceptor.java +++ b/src/main/java/org/folio/search/integration/message/interceptor/ResourceEventBatchInterceptor.java @@ -33,7 +33,7 @@ public class ResourceEventBatchInterceptor implements BatchInterceptor> { - - private final LinkedDataLccnProcessor linkedDataLccnProcessor; - - public LinkedDataAuthorityLccnProcessor(LccnNormalizer lccnNormalizer) { - this.linkedDataLccnProcessor = new LinkedDataLccnProcessor(lccnNormalizer); - } - - @Override - public Set getFieldValue(LinkedDataAuthority linkedDataAuthority) { - return linkedDataLccnProcessor.getFieldValue(linkedDataAuthority.getIdentifiers()); - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b484fca7d..4a2005c92 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -129,7 +129,7 @@ folio: group-id: ${folio.environment}-mod-search-location-type-group linked-data: concurrency: ${KAFKA_LINKED_DATA_CONCURRENCY:1} - topic-pattern: (${folio.environment}\.)(.*\.)linked-data\.(instance|work|authority) + topic-pattern: (${folio.environment}\.)(.*\.)linked-data\.(instance|work|hub) group-id: ${folio.environment}-mod-search-linked-data-group reindex-range-index: concurrency: ${KAFKA_REINDEX_RANGE_INDEX_CONCURRENCY:2} diff --git a/src/main/resources/elasticsearch/index/linked-data-authority.json b/src/main/resources/elasticsearch/index/linked-data-hub.json similarity index 100% rename from src/main/resources/elasticsearch/index/linked-data-authority.json rename to src/main/resources/elasticsearch/index/linked-data-hub.json diff --git a/src/main/resources/model/linked_data_authority.json b/src/main/resources/model/linked_data_authority.json deleted file mode 100644 index b1b312dec..000000000 --- a/src/main/resources/model/linked_data_authority.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "linked-data-authority", - "eventBodyJavaClass": "org.folio.search.domain.dto.LinkedDataAuthority", - "reindexSupported": true, - "fields": { - "id": { - "index": "keyword" - }, - "tenantId": { - "index": "keyword_lowercase", - "showInResponse": [ "search" ], - "isTenant": true - }, - "label": { - "index": "standard" - }, - "type": { - "index": "keyword" - }, - "identifiers": { - "type": "object", - "properties": { - "value": { - "index": "whitespace" - }, - "type": { - "index": "whitespace" - } - } - } - }, - "searchFields": { - "lccn": { - "type": "search", - "index": "keyword", - "processor": "linkedDataAuthorityLccnProcessor" - } - }, - "indexMappings": { } -} diff --git a/src/main/resources/model/linked_data_hub.json b/src/main/resources/model/linked_data_hub.json new file mode 100644 index 000000000..1caba8773 --- /dev/null +++ b/src/main/resources/model/linked_data_hub.json @@ -0,0 +1,29 @@ +{ + "name": "linked-data-hub", + "eventBodyJavaClass": "org.folio.search.domain.dto.LinkedDataHub", + "reindexSupported": true, + "fields": { + "id": { + "index": "keyword", + "searchAliases": [ "keyword" ] + }, + "originalId": { + "index": "keyword", + "searchAliases": [ "keyword" ] + }, + "tenantId": { + "index": "keyword_lowercase", + "showInResponse": [ "search" ], + "isTenant": true + }, + "hubAAP": { + "searchAliases": [ "aap", "keyword" ], + "index": "multilang" + }, + "title": { + "searchAliases": [ "keyword" ], + "index": "multilang" + } + }, + "indexMappings": { } +} diff --git a/src/main/resources/swagger.api/examples/result/linkedDataHubSearchResult.yaml b/src/main/resources/swagger.api/examples/result/linkedDataHubSearchResult.yaml new file mode 100644 index 000000000..ac06d6392 --- /dev/null +++ b/src/main/resources/swagger.api/examples/result/linkedDataHubSearchResult.yaml @@ -0,0 +1,10 @@ +value: + searchQuery: "query string" + content: + - id: "1" + originalId: "d292aac1-6f82-4828-93ae-c1b5cde1318a" + hubAAP: "hub AAP" + title: "hub title" + pageNumber: 0 + totalPages: 3 + totalRecords: 27 diff --git a/src/main/resources/swagger.api/examples/result/linkedDataSearchAuthorityResult.yaml b/src/main/resources/swagger.api/examples/result/linkedDataSearchAuthorityResult.yaml deleted file mode 100644 index a35956d7b..000000000 --- a/src/main/resources/swagger.api/examples/result/linkedDataSearchAuthorityResult.yaml +++ /dev/null @@ -1,12 +0,0 @@ -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 6e02962ad..913d8cdf3 100644 --- a/src/main/resources/swagger.api/mod-search.yaml +++ b/src/main/resources/swagger.api/mod-search.yaml @@ -136,8 +136,8 @@ paths: /search/linked-data/works: $ref: 'paths/search-linked-data/search-linked-data-works.yaml' - /search/linked-data/authorities: - $ref: 'paths/search-linked-data/search-linked-data-authorities.yaml' + /search/linked-data/hubs: + $ref: 'paths/search-linked-data/search-linked-data-hubs.yaml' /search/linked-data/instances: $ref: 'paths/search-linked-data/search-linked-data-instances.yaml' diff --git a/src/main/resources/swagger.api/paths/search-linked-data/search-linked-data-authorities.yaml b/src/main/resources/swagger.api/paths/search-linked-data/search-linked-data-hubs.yaml similarity index 57% rename from src/main/resources/swagger.api/paths/search-linked-data/search-linked-data-authorities.yaml rename to src/main/resources/swagger.api/paths/search-linked-data/search-linked-data-hubs.yaml index 3fb9ecfe9..2ef3b071e 100644 --- a/src/main/resources/swagger.api/paths/search-linked-data/search-linked-data-authorities.yaml +++ b/src/main/resources/swagger.api/paths/search-linked-data/search-linked-data-hubs.yaml @@ -1,7 +1,7 @@ get: - operationId: searchLinkedDataAuthorities - summary: Search Linked Data Authorities - description: Get a list of linked data authorities records for CQL query + operationId: searchLinkedDataHubs + summary: Search Linked Data Hubs + description: Get a list of linked data Hubs records for CQL query tags: - search parameters: @@ -11,14 +11,14 @@ get: - $ref: '../../parameters/offset-param.yaml' responses: '200': - description: 'Linked data authorities search result' + description: 'Linked data Hubs search result' content: application/json: schema: - $ref: '../../schemas/response/linkedDataAuthoritySearchResult.yaml' + $ref: '../../schemas/response/linkedDataHubSearchResult.yaml' examples: searchResult: - $ref: '../../examples/result/linkedDataSearchAuthorityResult.yaml' + $ref: '../../examples/result/linkedDataHubSearchResult.yaml' '400': $ref: '../../responses/badRequestResponse.yaml' '500': diff --git a/src/main/resources/swagger.api/schemas/dto/linked-data/linkedDataAuthority.yaml b/src/main/resources/swagger.api/schemas/dto/linked-data/linkedDataAuthority.yaml deleted file mode 100644 index f436e4cd9..000000000 --- a/src/main/resources/swagger.api/schemas/dto/linked-data/linkedDataAuthority.yaml +++ /dev/null @@ -1,21 +0,0 @@ -description: "Linked Data Authority search dto, contains Authority and Identifiers" -type: "object" -properties: - id: - description: "The Linked Data ID of an Authority" - type: "string" - tenantId: - description: "Tenant ID" - type: string - label: - description: "Value of Label" - type: "string" - type: - type: "string" - identifiers: - type: "array" - description: "Linked data authority identifier array" - items: - $ref: "common/linkedDataIdentifier.yaml" -required: - - "id" diff --git a/src/main/resources/swagger.api/schemas/dto/linked-data/linkedDataHub.yaml b/src/main/resources/swagger.api/schemas/dto/linked-data/linkedDataHub.yaml new file mode 100644 index 000000000..bc5313b17 --- /dev/null +++ b/src/main/resources/swagger.api/schemas/dto/linked-data/linkedDataHub.yaml @@ -0,0 +1,20 @@ +description: "Linked Data Hub search dto, contains Hub and Identifiers" +type: "object" +properties: + id: + description: "The Linked Data ID of an Hub" + type: "string" + originalId: + description: "Original RDF ID of an Hub" + type: "string" + tenantId: + description: "Tenant ID" + type: "string" + hubAAP: + description: "Hub AAP" + type: "string" + title: + description: "Hub Variant title" + type: "string" +required: + - "id" diff --git a/src/main/resources/swagger.api/schemas/request/reindexRequest.yaml b/src/main/resources/swagger.api/schemas/request/reindexRequest.yaml index 384eb1d46..9795f84d1 100644 --- a/src/main/resources/swagger.api/schemas/request/reindexRequest.yaml +++ b/src/main/resources/swagger.api/schemas/request/reindexRequest.yaml @@ -15,7 +15,7 @@ properties: - location - linked-data-instance - linked-data-work - - linked-data-authority + - linked-data-hub indexSettings: description: Index settings to apply for index $ref: "../../schemas/entity/indexSettings.yaml" diff --git a/src/main/resources/swagger.api/schemas/response/linkedDataAuthoritySearchResult.yaml b/src/main/resources/swagger.api/schemas/response/linkedDataHubSearchResult.yaml similarity index 66% rename from src/main/resources/swagger.api/schemas/response/linkedDataAuthoritySearchResult.yaml rename to src/main/resources/swagger.api/schemas/response/linkedDataHubSearchResult.yaml index 34fa1830d..efb9d2fb7 100644 --- a/src/main/resources/swagger.api/schemas/response/linkedDataAuthoritySearchResult.yaml +++ b/src/main/resources/swagger.api/schemas/response/linkedDataHubSearchResult.yaml @@ -1,4 +1,4 @@ -description: "Linked data authority search result response" +description: "Linked data Hub search result response" type: "object" properties: searchQuery: @@ -6,9 +6,9 @@ properties: description: "Initial search query" content: type: "array" - description: "List of linked data authority records found" + description: "List of linked data hub records found" items: - $ref: "../../schemas/dto/linked-data/linkedDataAuthority.yaml" + $ref: "../../schemas/dto/linked-data/linkedDataHub.yaml" pageNumber: type: "integer" description: "Current results page number, 0 by default" diff --git a/src/test/java/org/folio/search/controller/IndexManagementIT.java b/src/test/java/org/folio/search/controller/IndexManagementIT.java index 321ae6589..dae592306 100644 --- a/src/test/java/org/folio/search/controller/IndexManagementIT.java +++ b/src/test/java/org/folio/search/controller/IndexManagementIT.java @@ -120,7 +120,7 @@ void runReindex_positive_locations() throws Exception { } @ParameterizedTest - @EnumSource(value = ResourceType.class, names = {"LINKED_DATA_WORK", "LINKED_DATA_AUTHORITY"}) + @EnumSource(value = ResourceType.class, names = {"LINKED_DATA_WORK", "LINKED_DATA_HUB"}) void runReindex_shouldRecreate_linkedDataResourcesIndexes(ResourceType resourceType) throws Exception { var reindexRequest = new ReindexRequest() .resourceName(ResourceNameEnum.valueOf(resourceType.name())) diff --git a/src/test/java/org/folio/search/controller/SearchControllerTest.java b/src/test/java/org/folio/search/controller/SearchControllerTest.java index c0abe04ab..ddf4c3ad5 100644 --- a/src/test/java/org/folio/search/controller/SearchControllerTest.java +++ b/src/test/java/org/folio/search/controller/SearchControllerTest.java @@ -17,7 +17,7 @@ import java.util.stream.Stream; import org.folio.search.domain.dto.Authority; import org.folio.search.domain.dto.Instance; -import org.folio.search.domain.dto.LinkedDataAuthority; +import org.folio.search.domain.dto.LinkedDataHub; import org.folio.search.domain.dto.LinkedDataWork; import org.folio.search.exception.SearchOperationException; import org.folio.search.exception.SearchServiceException; @@ -87,7 +87,7 @@ void search_positive(Class requestClass, "/search/instances", "/search/authorities", "/search/linked-data/works", - "/search/linked-data/authorities", + "/search/linked-data/hubs", }) void search_offset_limit_10k(String searchPath) throws Exception { @@ -140,7 +140,7 @@ void search_negative_indexNotFound(Class requestClass, "Instances , 500 , /search/instances", "Authorities , 500 , /search/authorities", "LinkedDataWorks , 100 , /search/linked-data/works", - "LinkedDataAuthorities , 100 , /search/linked-data/authorities", + "LinkedDataHubs , 100 , /search/linked-data/hubs", }) void search_negative_invalidLimitParameter(String classMessagePart, int limit, String searchPass) throws Exception { var expectedMessage = String.format("search%s.limit must be less than or equal to %s", classMessagePart, limit); @@ -212,7 +212,7 @@ private static Stream provideSearchPaths() { Arguments.of(Instance.class, "/search/instances", false, 100, "$.instances"), Arguments.of(Authority.class, "/search/authorities", false, 100, "$.authorities"), Arguments.of(LinkedDataWork.class, "/search/linked-data/works", true, 10, "$.content"), - Arguments.of(LinkedDataAuthority.class, "/search/linked-data/authorities", true, 10, "$.content") + Arguments.of(LinkedDataHub.class, "/search/linked-data/hubs", true, 10, "$.content") ); } } diff --git a/src/test/java/org/folio/search/controller/SearchLinkedDataAuthorityIT.java b/src/test/java/org/folio/search/controller/SearchLinkedDataAuthorityIT.java deleted file mode 100644 index 2d48b3244..000000000 --- a/src/test/java/org/folio/search/controller/SearchLinkedDataAuthorityIT.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.folio.search.controller; - -import static org.folio.search.sample.SampleLinkedData.getAuthorityConceptSampleAsMap; -import static org.folio.search.sample.SampleLinkedData.getAuthorityPersonSampleAsMap; -import static org.folio.search.utils.LinkedDataTestUtils.toTotalRecords; -import static org.hamcrest.Matchers.is; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; - -import org.folio.search.domain.dto.LinkedDataAuthority; -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 SearchLinkedDataAuthorityIT extends BaseIntegrationTest { - - @BeforeAll - static void prepare() { - setUpTenant(LinkedDataAuthority.class, getAuthorityConceptSampleAsMap(), getAuthorityPersonSampleAsMap()); - } - - @AfterAll - static void cleanUp() { - removeTenant(); - } - - @DisplayName("search by linked data authority (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, 1, lccn = \"sh9876543210\"", - "12, 0, lccn = \"s h9876543210\"", - "13, 1, lccn = \"sh0123456789\"", - "14, 0, lccn = \"sh 0123456789\"", - "15, 1, lccn = \"n0123456789\"", - "16, 0, lccn = \"n 0123456789\"", - "17, 2, lccn any \"*0123456789\"", - "18, 1, lccn any \"*0123456789\" AND type = \"PERSON\"", - "19, 1, lccn any \"*0123456789\" AND type = \"CONCEPT\"" - }) - void searchByLinkedDataAuthority_parameterized_singleResult(int index, int size, String query) throws Throwable { - doSearchByLinkedDataAuthority(query) - .andExpect(jsonPath(toTotalRecords(), is(size))); - } -} diff --git a/src/test/java/org/folio/search/controller/SearchLinkedDataHubIT.java b/src/test/java/org/folio/search/controller/SearchLinkedDataHubIT.java new file mode 100644 index 000000000..586ce5b18 --- /dev/null +++ b/src/test/java/org/folio/search/controller/SearchLinkedDataHubIT.java @@ -0,0 +1,51 @@ +package org.folio.search.controller; + +import static org.folio.search.sample.SampleLinkedData.getHubSample2AsMap; +import static org.folio.search.sample.SampleLinkedData.getHubSampleAsMap; +import static org.folio.search.utils.LinkedDataTestUtils.toTotalRecords; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; + +import org.folio.search.domain.dto.LinkedDataHub; +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 SearchLinkedDataHubIT extends BaseIntegrationTest { + + @BeforeAll + static void prepare() { + setUpTenant(LinkedDataHub.class, getHubSampleAsMap(), getHubSample2AsMap()); + } + + @AfterAll + static void cleanUp() { + removeTenant(); + } + + @DisplayName("search by linked data hub") + @ParameterizedTest(name = "[{0}] {2}") + @CsvSource(value = { + " 1, 2, id any \"*\"", + " 2, 1, id = \"123\"", + " 3, 1, id = \"456\"", + " 4, 2, originalId = \"*\"", + " 5, 1, originalId = \"995ff81e-0ab6-4124-9e45-d6fa73c78d66\"", + " 6, 1, originalId = \"1d6f83d6-841b-4e01-8e03-1559a683b567\"", + " 7, 2, hubAAP = \"*\"", + " 8, 1, hubAAP = \"*ABC\"", + " 9, 1, hubAAP = \"*XYZ\"", + "10, 2, title = \"*\"", + "11, 1, title = \"HubTitleABC\"", + "12, 1, title = \"HubTitleXYZ\"" + }) + void searchByLinkedDataHub_parameterized_singleResult(int index, int size, String query) throws Throwable { + doSearchByLinkedDataHub(query) + .andExpect(jsonPath(toTotalRecords(), is(size))); + } +} diff --git a/src/test/java/org/folio/search/integration/KafkaMessageListenerTest.java b/src/test/java/org/folio/search/integration/KafkaMessageListenerTest.java index 3652005c2..4e1cb80e0 100644 --- a/src/test/java/org/folio/search/integration/KafkaMessageListenerTest.java +++ b/src/test/java/org/folio/search/integration/KafkaMessageListenerTest.java @@ -9,7 +9,7 @@ import static org.folio.search.domain.dto.ResourceEventType.UPDATE; import static org.folio.search.model.types.ResourceType.AUTHORITY; import static org.folio.search.model.types.ResourceType.INSTANCE; -import static org.folio.search.model.types.ResourceType.LINKED_DATA_AUTHORITY; +import static org.folio.search.model.types.ResourceType.LINKED_DATA_HUB; import static org.folio.search.model.types.ResourceType.LINKED_DATA_INSTANCE; import static org.folio.search.model.types.ResourceType.LINKED_DATA_WORK; import static org.folio.search.utils.TestConstants.INVENTORY_INSTANCE_TOPIC; @@ -21,7 +21,7 @@ import static org.folio.search.utils.TestConstants.inventoryHoldingTopic; import static org.folio.search.utils.TestConstants.inventoryInstanceTopic; import static org.folio.search.utils.TestConstants.inventoryItemTopic; -import static org.folio.search.utils.TestConstants.linkedDataAuthorityTopic; +import static org.folio.search.utils.TestConstants.linkedDataHubTopic; import static org.folio.search.utils.TestConstants.linkedDataInstanceTopic; import static org.folio.search.utils.TestConstants.linkedDataWorkTopic; import static org.folio.search.utils.TestUtils.OBJECT_MAPPER; @@ -45,7 +45,7 @@ import java.util.function.BiConsumer; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.folio.search.domain.dto.Authority; -import org.folio.search.domain.dto.LinkedDataAuthority; +import org.folio.search.domain.dto.LinkedDataHub; import org.folio.search.domain.dto.LinkedDataInstance; import org.folio.search.domain.dto.LinkedDataWork; import org.folio.search.domain.dto.ResourceEvent; @@ -285,23 +285,23 @@ void handleLinkedDataWorkEvent_negative_logFailedEvent() { } @Test - void handleLinkedDataAuthorityEvent_positive() { - var payload = toMap(new LinkedDataAuthority().id(RESOURCE_ID)); + void handleLinkedDataHubEvent_positive() { + var payload = toMap(new LinkedDataHub().id(RESOURCE_ID)); messageListener.handleLinkedDataEvents(List.of(new ConsumerRecord<>( - linkedDataAuthorityTopic(TENANT_ID), 0, 0, RESOURCE_ID, - resourceEvent(null, LINKED_DATA_AUTHORITY, CREATE, payload, null)))); + linkedDataHubTopic(TENANT_ID), 0, 0, RESOURCE_ID, + resourceEvent(null, LINKED_DATA_HUB, CREATE, payload, null)))); var expectedEvents = singletonList( - resourceEvent(RESOURCE_ID, LINKED_DATA_AUTHORITY, CREATE, payload, null)); + resourceEvent(RESOURCE_ID, LINKED_DATA_HUB, CREATE, payload, null)); verify(resourceService).indexResources(expectedEvents); verify(batchProcessor).consumeBatchWithFallback(eq(expectedEvents), eq(KAFKA_RETRY_TEMPLATE_NAME), any(), any()); } @Test - void handleLinkedDataAuthorityEvent_negative_logFailedEvent() { - var payload = toMap(new LinkedDataAuthority().id(RESOURCE_ID)); - var expectedEvents = List.of(resourceEvent(RESOURCE_ID, LINKED_DATA_AUTHORITY, UPDATE, payload, null)); + void handleLinkedDataHubEvent_negative_logFailedEvent() { + var payload = toMap(new LinkedDataHub().id(RESOURCE_ID)); + var expectedEvents = List.of(resourceEvent(RESOURCE_ID, LINKED_DATA_HUB, UPDATE, payload, null)); doAnswer(inv -> { inv.>getArgument(3).accept(expectedEvents.get(0), new Exception("error")); @@ -309,8 +309,8 @@ void handleLinkedDataAuthorityEvent_negative_logFailedEvent() { }).when(batchProcessor).consumeBatchWithFallback(eq(expectedEvents), eq(KAFKA_RETRY_TEMPLATE_NAME), any(), any()); messageListener.handleLinkedDataEvents(List.of(new ConsumerRecord<>( - linkedDataAuthorityTopic(TENANT_ID), 0, 0, RESOURCE_ID, - resourceEvent(null, LINKED_DATA_AUTHORITY, UPDATE, payload, null)))); + linkedDataHubTopic(TENANT_ID), 0, 0, RESOURCE_ID, + resourceEvent(null, LINKED_DATA_HUB, UPDATE, payload, null)))); verify(batchProcessor).consumeBatchWithFallback(eq(expectedEvents), eq(KAFKA_RETRY_TEMPLATE_NAME), any(), any()); } diff --git a/src/test/java/org/folio/search/sample/SampleLinkedData.java b/src/test/java/org/folio/search/sample/SampleLinkedData.java index 487c6c037..93ab800b8 100644 --- a/src/test/java/org/folio/search/sample/SampleLinkedData.java +++ b/src/test/java/org/folio/search/sample/SampleLinkedData.java @@ -26,12 +26,12 @@ public static Map getWork2SampleAsMap() { return readJson("/samples/linked-data/work2.json"); } - public static Map getAuthorityConceptSampleAsMap() { - return readJson("/samples/linked-data/authority_concept.json"); + public static Map getHubSampleAsMap() { + return readJson("/samples/linked-data/hub.json"); } - public static Map getAuthorityPersonSampleAsMap() { - return readJson("/samples/linked-data/authority_person.json"); + public static Map getHubSample2AsMap() { + return readJson("/samples/linked-data/hub2.json"); } private static Map readJson(String path) { diff --git a/src/test/java/org/folio/search/service/IndexServiceTest.java b/src/test/java/org/folio/search/service/IndexServiceTest.java index 0f6b27579..fbffc0a9f 100644 --- a/src/test/java/org/folio/search/service/IndexServiceTest.java +++ b/src/test/java/org/folio/search/service/IndexServiceTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.folio.search.domain.dto.ReindexRequest.ResourceNameEnum.LINKED_DATA_AUTHORITY; +import static org.folio.search.domain.dto.ReindexRequest.ResourceNameEnum.LINKED_DATA_HUB; import static org.folio.search.domain.dto.ReindexRequest.ResourceNameEnum.LINKED_DATA_WORK; import static org.folio.search.model.types.ResourceType.AUTHORITY; import static org.folio.search.model.types.ResourceType.CAMPUS; @@ -474,7 +474,7 @@ void reindexInventory_positive_locationsAndRecreateIndex() { } @ParameterizedTest - @EnumSource(value = ResourceType.class, names = {"LINKED_DATA_WORK", "LINKED_DATA_AUTHORITY"}) + @EnumSource(value = ResourceType.class, names = {"LINKED_DATA_WORK", "LINKED_DATA_HUB"}) void reindexInventory_shouldRecreate_linkedDataResourcesIndexes(ResourceType resourceType) { var linkedDataResourceIndex = getIndexName(resourceType, TENANT_ID); when(resourceDescriptionService.find(resourceType)).thenReturn( @@ -579,7 +579,7 @@ private static Stream tenantIdAndReindexRequestDataProvider() { ), arguments( TENANT_ID, - new ReindexRequest().resourceName(LINKED_DATA_AUTHORITY) + new ReindexRequest().resourceName(LINKED_DATA_HUB) ), arguments( MEMBER_TENANT_ID, @@ -587,7 +587,7 @@ private static Stream tenantIdAndReindexRequestDataProvider() { ), arguments( MEMBER_TENANT_ID, - new ReindexRequest().resourceName(LINKED_DATA_AUTHORITY).recreateIndex(true) + new ReindexRequest().resourceName(LINKED_DATA_HUB).recreateIndex(true) ) ); } 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 796fb0fc2..da6f695b0 100644 --- a/src/test/java/org/folio/search/support/base/ApiEndpoints.java +++ b/src/test/java/org/folio/search/support/base/ApiEndpoints.java @@ -109,8 +109,8 @@ public static String linkedDataWorkSearchPath() { return "/search/linked-data/works"; } - public static String linkedDataAuthoritySearchPath() { - return "/search/linked-data/authorities"; + public static String linkedDataHubSearchPath() { + return "/search/linked-data/hubs"; } public static String authorityBrowsePath() { 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 7f68e81d1..7d71320cb 100644 --- a/src/test/java/org/folio/search/support/base/BaseIntegrationTest.java +++ b/src/test/java/org/folio/search/support/base/BaseIntegrationTest.java @@ -11,7 +11,7 @@ import static org.folio.search.model.types.ResourceType.AUTHORITY; import static org.folio.search.support.base.ApiEndpoints.authoritySearchPath; import static org.folio.search.support.base.ApiEndpoints.instanceSearchPath; -import static org.folio.search.support.base.ApiEndpoints.linkedDataAuthoritySearchPath; +import static org.folio.search.support.base.ApiEndpoints.linkedDataHubSearchPath; import static org.folio.search.support.base.ApiEndpoints.linkedDataInstanceSearchPath; import static org.folio.search.support.base.ApiEndpoints.linkedDataWorkSearchPath; import static org.folio.search.utils.SearchUtils.getIndexName; @@ -19,7 +19,7 @@ import static org.folio.search.utils.TestConstants.MEMBER_TENANT_ID; import static org.folio.search.utils.TestConstants.TENANT_ID; import static org.folio.search.utils.TestConstants.inventoryAuthorityTopic; -import static org.folio.search.utils.TestConstants.linkedDataAuthorityTopic; +import static org.folio.search.utils.TestConstants.linkedDataHubTopic; import static org.folio.search.utils.TestConstants.linkedDataInstanceTopic; import static org.folio.search.utils.TestConstants.linkedDataWorkTopic; import static org.folio.search.utils.TestUtils.asJsonString; @@ -53,7 +53,7 @@ import org.folio.search.domain.dto.Authority; import org.folio.search.domain.dto.FeatureConfig; import org.folio.search.domain.dto.Instance; -import org.folio.search.domain.dto.LinkedDataAuthority; +import org.folio.search.domain.dto.LinkedDataHub; import org.folio.search.domain.dto.LinkedDataInstance; import org.folio.search.domain.dto.LinkedDataWork; import org.folio.search.domain.dto.ResourceEvent; @@ -201,8 +201,8 @@ protected static ResultActions doSearchByLinkedDataWorkWithoutInstances(String q } @SneakyThrows - protected static ResultActions doSearchByLinkedDataAuthority(String query) { - return doSearch(linkedDataAuthoritySearchPath(), TENANT_ID, Map.of("query", query)); + protected static ResultActions doSearchByLinkedDataHub(String query) { + return doSearch(linkedDataHubSearchPath(), TENANT_ID, Map.of("query", query)); } @SneakyThrows @@ -368,10 +368,10 @@ protected static void setUpTenant(Class type, String tenant, Runnable postIni ); } - if (type.equals(LinkedDataAuthority.class)) { - setUpTenant(tenant, linkedDataAuthoritySearchPath(), postInitAction, asList(records), expectedCount, matchers, - ldAuthority -> kafkaTemplate.send(linkedDataAuthorityTopic(tenant), - resourceEvent(tenant, ResourceType.LINKED_DATA_AUTHORITY, CREATE, ldAuthority)) + if (type.equals(LinkedDataHub.class)) { + setUpTenant(tenant, linkedDataHubSearchPath(), postInitAction, asList(records), expectedCount, matchers, + ldHub -> kafkaTemplate.send(linkedDataHubTopic(tenant), + resourceEvent(tenant, ResourceType.LINKED_DATA_HUB, CREATE, ldHub)) ); } } diff --git a/src/test/java/org/folio/search/utils/TestConstants.java b/src/test/java/org/folio/search/utils/TestConstants.java index e50a52f09..c2ef0011f 100644 --- a/src/test/java/org/folio/search/utils/TestConstants.java +++ b/src/test/java/org/folio/search/utils/TestConstants.java @@ -36,7 +36,7 @@ public class TestConstants { public static final String CONSORTIUM_INSTANCE_TOPIC = "search.consortium.instance"; public static final String LINKED_DATA_WORK_INSTANCE = "linked-data.instance"; public static final String LINKED_DATA_WORK_TOPIC = "linked-data.work"; - public static final String LINKED_DATA_AUTHORITY_TOPIC = "linked-data.authority"; + public static final String LINKED_DATA_HUB_TOPIC = "linked-data.hub"; public static final String CAMPUS_TOPIC = "inventory.campus"; public static final String INSTITUTION_TOPIC = "inventory.institution"; public static final String LIBRARY_TOPIC = "inventory.library"; @@ -140,8 +140,8 @@ public static String linkedDataWorkTopic(String tenantId) { return getTopicName(tenantId, LINKED_DATA_WORK_TOPIC); } - public static String linkedDataAuthorityTopic(String tenantId) { - return getTopicName(tenantId, LINKED_DATA_AUTHORITY_TOPIC); + public static String linkedDataHubTopic(String tenantId) { + return getTopicName(tenantId, LINKED_DATA_HUB_TOPIC); } public static String inventoryCampusTopic(String tenantId) { diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 6834622aa..89a754aeb 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -106,7 +106,7 @@ folio: - name: linked-data.work numPartitions: 1 replicationFactor: 1 - - name: linked-data.authority + - name: linked-data.hub numPartitions: 1 replicationFactor: 1 - name: inventory.campus @@ -147,7 +147,7 @@ folio: group-id: ${folio.environment}-mod-search-location-type-group linked-data: concurrency: 1 - topic-pattern: (${folio.environment}\.)(.*\.)linked-data\.(instance|work|authority) + topic-pattern: (${folio.environment}\.)(.*\.)linked-data\.(instance|work|hub) group-id: ${folio.environment}-mod-search-linked-data-group reindex-range-index: concurrency: 1 diff --git a/src/test/resources/samples/linked-data/authority_concept.json b/src/test/resources/samples/linked-data/authority_concept.json deleted file mode 100644 index 04205f469..000000000 --- a/src/test/resources/samples/linked-data/authority_concept.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id": "123456654321", - "label": "concept-label", - "type": "CONCEPT", - "identifiers": [ - { - "value": "sh 0123456789", - "type": "LCCN" - }, - { - "value": "sh 9876543210", - "type": "LCCN" - } - ] -} diff --git a/src/test/resources/samples/linked-data/authority_person.json b/src/test/resources/samples/linked-data/authority_person.json deleted file mode 100644 index ceb3e408a..000000000 --- a/src/test/resources/samples/linked-data/authority_person.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "123456654322", - "label": "person-label", - "type": "PERSON", - "identifiers": [ - { - "value": "n 0123456789", - "type": "LCCN" - } - ] -} diff --git a/src/test/resources/samples/linked-data/hub.json b/src/test/resources/samples/linked-data/hub.json new file mode 100644 index 000000000..d58f8af55 --- /dev/null +++ b/src/test/resources/samples/linked-data/hub.json @@ -0,0 +1,6 @@ +{ + "id": "123", + "originalId": "995ff81e-0ab6-4124-9e45-d6fa73c78d66", + "hubAAP": "Hub AAP ABC", + "title": "HubTitleABC" +} diff --git a/src/test/resources/samples/linked-data/hub2.json b/src/test/resources/samples/linked-data/hub2.json new file mode 100644 index 000000000..3352d34b7 --- /dev/null +++ b/src/test/resources/samples/linked-data/hub2.json @@ -0,0 +1,6 @@ +{ + "id": "456", + "originalId": "1d6f83d6-841b-4e01-8e03-1559a683b567", + "hubAAP": "Hub AAP XYZ", + "title": "HubTitleXYZ" +}