diff --git a/NEWS.md b/NEWS.md index 7d7763f52..94134d6c2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,7 +7,7 @@ * Requires `API_NAME vX.Y` ### Features -* Description ([ISSUE](https://folio-org.atlassian.net/browse/ISSUE)) +* Migrate Package Endpoints to HoldingsIQ v2 API ([MODKBEKBJ-804](https://folio-org.atlassian.net/browse/MODKBEKBJ-804)) ### Bug fixes * Fix offset handling when retrieving holdings from HoldingsIQ. ([MODKBEKBJ-825](https://folio-org.atlassian.net/browse/MODKBEKBJ-825)) diff --git a/pom.xml b/pom.xml index 5cc307d6b..1ef2afe8f 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ 36.0.0 4.0.0 6.0.0 - 5.0.0 + 6.0.0-SNAPSHOT 1.11.0 5.1.2 @@ -50,7 +50,6 @@ 1.22.0 1.11.0 1.18.46 - 4.4.16 5.12.0 3.20.0 @@ -61,11 +60,12 @@ 7.0.8 - 4.13.2 + 6.1.0 6.0.0 5.23.0 3.27.7 1.5.3 + 3.13.2 5.0.0 @@ -88,24 +88,6 @@ 13.6.0 - - - default - - true - - - false - - - - no-coverage - - true - - - - @@ -129,6 +111,13 @@ pom import + + org.junit + junit-bom + ${junit.version} + pom + import + @@ -195,11 +184,6 @@ ${lombok.version} provided - - org.apache.httpcomponents - httpcore - ${httpcore.version} - org.folio folio-di-support @@ -240,22 +224,27 @@ + + org.junit.jupiter + junit-jupiter + test + io.vertx - vertx-unit + vertx-junit5 test - junit - junit - ${junit.version} + org.springframework + spring-test + ${spring.version} + test + + + org.folio + postgres-testing + ${rmb.version} test - - - org.hamcrest - hamcrest-core - - io.rest-assured @@ -275,6 +264,12 @@ ${mockito.version} test + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + org.assertj assertj-core @@ -288,37 +283,9 @@ test - org.folio - folio-service-tools-test - ${folio-service-tools.version} - - - org.junit.jupiter - junit-jupiter-engine - - - org.junit.jupiter - junit-jupiter-api - - - org.junit.platform - junit-platform-engine - - - org.junit.platform - junit-platform-commons - - - org.apache.logging.log4j - log4j-slf4j2-impl - - - test - - - org.springframework - spring-test - ${spring.version} + org.wiremock + wiremock + ${wiremock.version} test @@ -686,15 +653,11 @@ ${maven-surefire-plugin.version} false - - **/org/folio/rest/impl/integrationsuite/*.java - **/Test*.java **/*Test.java **/*Tests.java **/*TestCase.java - org/folio/rest/impl/IntegrationTestSuite.java @@ -709,9 +672,6 @@ prepare-agent - - ${test.coverage.skip} - jacoco-coverage-report @@ -719,9 +679,6 @@ report - - ${test.coverage.skip} - diff --git a/ramls/packages.raml b/ramls/packages.raml index f45fc4494..205935605 100644 --- a/ramls/packages.raml +++ b/ramls/packages.raml @@ -11,9 +11,10 @@ documentation: traits: queriable: !include traits/queriable.raml + packageQueriable: !include traits/packageQueriable.raml sortable: !include traits/sortable.raml pageable: !include traits/pageable.raml - filterable: !include traits/filterable.raml + packageFilterable: !include traits/packageFilterable.raml taggable: !include traits/taggable.raml accessible: !include traits/accessible.raml packageResourcesFilterable: !include traits/packageResourcesFilterable.raml @@ -34,7 +35,7 @@ types: displayName: Packages get: description: Retrieve a collection of packages based on the search query. - is: [queriable, filterable, taggable, accessible, + is: [packageQueriable, packageFilterable, taggable, accessible, sortable: {defaultValue: 'relevance', possibleValues: 'name, relevance'}, pageable: {maxCountValue: 100, defaultCountValue: 25}] queryParameters: diff --git a/ramls/providers.raml b/ramls/providers.raml index f04629cac..a81ae4c3b 100644 --- a/ramls/providers.raml +++ b/ramls/providers.raml @@ -22,7 +22,8 @@ traits: queriable: !include traits/queriable.raml sortable: !include traits/sortable.raml pageable: !include traits/pageable.raml - filterable: !include traits/filterable.raml + packageFilterable: !include traits/packageFilterable.raml + packageQueriable: !include traits/packageQueriable.raml taggable: !include traits/taggable.raml accessible: !include traits/accessible.raml includable: !include traits/includePackages.raml @@ -128,7 +129,7 @@ traits: /packages: get: description: Search within a list of packages associated with a given provider. - is: [queriable, taggable, accessible, filterable, + is: [packageQueriable, taggable, accessible, packageFilterable, sortable: {defaultValue: 'relevance', possibleValues: 'name, relevance'}, pageable: {maxCountValue: 100, defaultCountValue: 25}] responses: diff --git a/ramls/traits/filterable.raml b/ramls/traits/filterable.raml deleted file mode 100644 index ba50e9af1..000000000 --- a/ramls/traits/filterable.raml +++ /dev/null @@ -1,16 +0,0 @@ -queryParameters: - filter[selected]: - displayName: Selection status - type: string - description: Filter to narrow down results based on selection status. Possible values are all, true, false, ebsco. - example: all - required: false - filter[type]: - displayName: Content type - type: string - description: | - Filter to narrow down results based on content type. Defaults to all. - Possible values are all, aggregatedfulltext, abstractandindex, ebook, ejournal, print, unknown, streamingmedia, mixedcontent, onlinereference. - example: ebook - default: all - required: false diff --git a/ramls/traits/packageFilterable.raml b/ramls/traits/packageFilterable.raml new file mode 100644 index 000000000..7b4933555 --- /dev/null +++ b/ramls/traits/packageFilterable.raml @@ -0,0 +1,33 @@ +queryParameters: + filter[selected]: + displayName: Selection status + type: string + description: Filter to narrow down results based on selection status. Possible values are all, true, false, ebsco. + example: all + required: false + filter[type]: + displayName: Content type + type: string + description: | + Filter to narrow down results based on content type. Defaults to all. + Possible values: all, aggregatedfulltext, abstractandindex, ebook, ejournal, print, unknown, streamingmedia, mixedcontent, onlinereference. + example: ebook + default: all + required: false + filter[visibility]: + displayName: Visibility status + type: string + description: | + Limits the results based on customer visibility status per product category. + Only functions when selection=selected is included in the request. + Possible values: visibleInPF, visibleInFTF, visibleInMARC, hiddenInPF, hiddenInFTF, hiddenInMARC + example: visibleInPF + required: false + filter[access]: + displayName: Package access + type: string + description: | + Limits the results based on Package Free Access. + Possible values: public, controlled + example: public + required: false diff --git a/ramls/traits/packageQueriable.raml b/ramls/traits/packageQueriable.raml new file mode 100644 index 000000000..0bd12f79e --- /dev/null +++ b/ramls/traits/packageQueriable.raml @@ -0,0 +1,27 @@ +queryParameters: + q: + displayName: Search query + type: string + description: String used to search to retrieve a collection + example: ABC-CLIO + required: false + q[field]: + displayName: Search field + type: string + description: | + Field to search. + name - Searches on Package Names and Alternative Names. + keyword - Searches on Package Name, Alternative Name, Vendor Name, Managed Description and Custom Description. + default: name + q[type]: + displayName: Search type + type: string + description: | + Type of search to be performed. + Possible values: exactphrase, advanced, any, contains, exactmatch, beginswith + highlight: + displayName: Hit highlighting + type: boolean + description: If enabled, highlight which parts of the Package result were matched on during searching + required: false + default: false \ No newline at end of file diff --git a/ramls/types/packages/packageAltName.json b/ramls/types/packages/packageAltName.json new file mode 100644 index 000000000..9779a9e51 --- /dev/null +++ b/ramls/types/packages/packageAltName.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Alternate names schema", + "description": "Alternate names schema", + "javaType": "org.folio.rest.jaxrs.model.PackageAltName", + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "integer", + "description": "The id of the alternate name of the package." + }, + "altName": { + "type": "string", + "description": "The alternate name of the package" + } + }, + "required": [ + "altName" + ] +} diff --git a/ramls/types/packages/packageDataAttributes.json b/ramls/types/packages/packageDataAttributes.json index e202821ad..2bbc171c2 100644 --- a/ramls/types/packages/packageDataAttributes.json +++ b/ramls/types/packages/packageDataAttributes.json @@ -6,86 +6,147 @@ "type": "object", "additionalProperties": false, "properties": { + "allowKbToAddTitles": { + "description": "Allow KB to add titles", + "example": true, + "type": "boolean" + }, "contentType": { - "type": "string", + "$ref": "contentTypeEnum.json", "description": "Content Type of Package", - "$ref" : "contentTypeEnum.json", - "example": "Online Reference" + "example": "Online Reference", + "type": "string" + }, + "customAltNames": { + "description": "The list of custom alternate names for the package", + "items": { + "$ref": "packageAltName.json", + "type": "object" + }, + "type": "array" }, "customCoverage": { - "type": "object", + "$ref": "../coverage.json", "description": "Custom Coverage", - "$ref": "../coverage.json" + "type": "object" + }, + "customDescription": { + "description": "The custom description of the package", + "example": "Package of medicinal journals (custom)", + "type": "string" + }, + "customDisplayName": { + "description": "The custom description of the package", + "type": "string" + }, + "isAvailableForSelection": { + "description": "Whether this package is available for full selection or not", + "example": false, + "type": "boolean" }, "isCustom": { - "type": "boolean", "description": "Whether this package is custom or not", - "example": false + "example": false, + "type": "boolean" + }, + "isFreeAccess": { + "description": "Whether this package has free access designation or not", + "example": false, + "type": "boolean" + }, + "isPrimaryPackage": { + "description": "Whether this package is a vendor's primary package", + "example": false, + "type": "boolean" }, "isSelected": { - "type": "boolean", "description": "Whether this package is selected or not", - "example": false + "example": false, + "type": "boolean" + }, + "managedAltNames": { + "description": "The list of managed alternate names for the package", + "items": { + "$ref": "packageAltName.json", + "type": "object" + }, + "type": "array" + }, + "managedDescription": { + "description": "The managed description of the package", + "example": "Package of medicinal journals", + "type": "string" }, "name": { - "type": "string", "description": "Package name", - "example": "Shenbao" + "example": "Shenbao", + "type": "string" }, "packageId": { - "type": "integer", "description": "Package Id", - "example": 1152699 + "example": 1152699, + "type": "integer" + }, + "packageToken": { + "$ref": "../token.json", + "description": "Package Token", + "type": "object" }, "packageType": { - "type": "string", "description": "Package type", - "example": "Complete" + "example": "Complete", + "type": "string" }, "providerId": { - "type": "integer", "description": "Provider Id", - "example": 91525 + "example": 91525, + "type": "integer" }, "providerName": { - "type": "string", "description": "Provider name", - "example": "Green Apple - Qingpingguo" + "example": "Green Apple - Qingpingguo", + "type": "string" + }, + "proxiedUrl": { + "description": "URL with proxy applied", + "type": "string" + }, + "proxy": { + "$ref": "../proxy.json", + "description": "Proxy", + "type": "object" }, "selectedCount": { - "type": "integer", "description": "Selected count", - "example": 0 + "example": 0, + "type": "integer" + }, + "tags": { + "$ref": "../../raml-util/schemas/tags.schema", + "description": "Package tags", + "type": "object" }, "titleCount": { - "type": "integer", "description": "Title count", - "example": 1 + "example": 1, + "type": "integer" + }, + "url": { + "description": "Package URL", + "type": "string" + }, + "visibility": { + "description": "Visibility details", + "items": { + "$ref": "packageVisibility.json", + "type": "object" + }, + "type": "array" }, "visibilityData": { "type": "object", "description": "Visibility data", "$ref": "../visibilityData.json" - }, - "allowKbToAddTitles": { - "type": "boolean", - "description": "Allow KB to add titles", - "example": true - }, - "packageToken": { - "type": "object", - "description": "Package Token", - "$ref": "../token.json" - }, - "proxy": { - "type": "object", - "description": "Proxy", - "$ref": "../proxy.json" - }, - "tags": { - "type": "object", - "description": "Package tags", - "$ref": "../../raml-util/schemas/tags.schema" } } } diff --git a/ramls/types/packages/packagePutDataAttributes.json b/ramls/types/packages/packagePutDataAttributes.json index 1cc39ca20..90ef096cb 100644 --- a/ramls/types/packages/packagePutDataAttributes.json +++ b/ramls/types/packages/packagePutDataAttributes.json @@ -6,62 +6,96 @@ "type": "object", "additionalProperties": false, "properties": { + "accessTypeId": { + "$ref": "../../raml-util/schemas/uuid.schema", + "description": "Access type id", + "example": "f973c3b6-85fc-4d35-bda8-f31b568957bf", + "type": "string" + }, + "allowKbToAddTitles": { + "description": "Allow KB to add titles", + "example": true, + "type": "boolean" + }, "contentType": { - "type": "string", + "$ref": "contentTypeEnum.json", "description": "Content Type of Package", - "$ref" : "contentTypeEnum.json", - "example": "Online Reference" + "example": "Online Reference", + "type": "string" }, - "accessTypeId": { - "type": "string", - "description": "Access type id", - "$ref": "../../raml-util/schemas/uuid.schema", - "example": "f973c3b6-85fc-4d35-bda8-f31b568957bf" + "customAltNames": { + "description": "The list of custom alternate names for the package", + "items": { + "$ref": "packageAltName.json", + "type": "object" + }, + "type": "array" }, "customCoverage": { - "type": "object", + "$ref": "../coverage.json", "description": "Custom Coverage", - "$ref": "../coverage.json" + "type": "object" + }, + "customDescription": { + "description": "The custom description of the package", + "example": "Package of medicinal journals (custom)", + "type": "string" + }, + "customDisplayName": { + "description": "The custom description of the package", + "type": "string" }, "isCustom": { - "type": "boolean", "description": "Whether this package is custom or not", - "example": false + "example": false, + "type": "boolean" }, - "isSelected": { - "type": "boolean", - "description": "Whether this package is selected or not", - "example": false + "isFreeAccess": { + "description": "Whether this package has free access designation or not", + "example": false, + "type": "boolean" }, "isFullPackage": { - "type": "boolean", "description": "Whether this package is partially selected or not", - "example": false + "example": false, + "type": "boolean" + }, + "isSelected": { + "description": "Whether this package is selected or not", + "example": false, + "type": "boolean" }, "name": { - "type": "string", "description": "Package name", - "example": "Shenbao" - }, - "visibilityData": { - "type": "object", - "description": "Visibility data", - "$ref": "../visibilityData.json" - }, - "allowKbToAddTitles": { - "type": "boolean", - "description": "Allow KB to add titles", - "example": true + "example": "Shenbao", + "type": "string" }, "packageToken": { - "type": "object", + "$ref": "../token.json", "description": "Package Token", - "$ref": "../token.json" + "type": "object" }, "proxy": { - "type": "object", + "$ref": "../proxy.json", "description": "Proxy", - "$ref": "../proxy.json" + "type": "object" + }, + "url": { + "description": "Package URL", + "type": "string" + }, + "visibility": { + "description": "Visibility details", + "items": { + "$ref": "packageVisibility.json", + "type": "object" + }, + "type": "array" + }, + "visibilityData": { + "type": "object", + "description": "Visibility data", + "$ref": "../visibilityData.json" } } } diff --git a/ramls/types/packages/packageVisibility.json b/ramls/types/packages/packageVisibility.json new file mode 100644 index 000000000..a33e5d7fa --- /dev/null +++ b/ramls/types/packages/packageVisibility.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Visibility details schema", + "description": "Visibility details schema", + "javaType": "org.folio.rest.jaxrs.model.PackageVisibility", + "type": "object", + "additionalProperties": false, + "properties": { + "category": { + "type": "string", + "description": "Visibility category", + "enum": [ + "PF", + "FTF", + "MARC" + ] + }, + "reason": { + "type": "string", + "description": "Reason the resource was hidden" + }, + "hidden": { + "type": "boolean", + "description": "Hidden status" + } + }, + "required": [ + "category", + "hidden" + ] +} diff --git a/src/main/java/org/folio/client/uc/UcApigeeEbscoClientImpl.java b/src/main/java/org/folio/client/uc/UcApigeeEbscoClientImpl.java index d5807fba4..debf87d78 100644 --- a/src/main/java/org/folio/client/uc/UcApigeeEbscoClientImpl.java +++ b/src/main/java/org/folio/client/uc/UcApigeeEbscoClientImpl.java @@ -1,5 +1,6 @@ package org.folio.client.uc; +import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON; import static org.folio.util.FutureUtils.mapVertxFuture; import io.vertx.core.Completable; @@ -22,8 +23,7 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import lombok.extern.log4j.Log4j2; -import org.apache.http.HttpHeaders; -import org.apache.http.entity.ContentType; +import org.folio.HttpHeaders; import org.folio.client.uc.configuration.GetPackageUcConfiguration; import org.folio.client.uc.configuration.GetTitlePackageUcConfiguration; import org.folio.client.uc.configuration.GetTitleUcConfiguration; @@ -133,7 +133,7 @@ public CompletableFuture getUsageMetricType(UcConfiguration config private Completable> handleResponse(Promise> promise) { return (response, failure) -> { if (failure != null) { - if (ContentType.APPLICATION_JSON.getMimeType().equals(response.getHeader(HttpHeaders.CONTENT_TYPE))) { + if (APPLICATION_JSON.toString().equalsIgnoreCase(response.getHeader(HttpHeaders.CONTENT_TYPE))) { JsonObject body = response.bodyAsJsonObject(); promise.fail(new UcFailedRequestException(response.statusCode(), body)); } diff --git a/src/main/java/org/folio/common/ListUtils.java b/src/main/java/org/folio/common/ListUtils.java index a82d9112c..462e9776f 100644 --- a/src/main/java/org/folio/common/ListUtils.java +++ b/src/main/java/org/folio/common/ListUtils.java @@ -21,6 +21,13 @@ public static List mapItems(Collection source, Function List mapItemsNullable(Collection source, Function mapper) { + if (source == null) { + return null; + } + return source.stream().map(mapper).collect(Collectors.toList()); + } + public static String createPlaceholders(int size) { return String.join(",", Collections.nCopies(size, "?")); } diff --git a/src/main/java/org/folio/properties/common/SearchProperties.java b/src/main/java/org/folio/properties/common/SearchProperties.java index 79a77554d..d1ae89d7e 100644 --- a/src/main/java/org/folio/properties/common/SearchProperties.java +++ b/src/main/java/org/folio/properties/common/SearchProperties.java @@ -1,3 +1,7 @@ package org.folio.properties.common; -public record SearchProperties(String titlesSearchType, String packagesSearchType) { } +public record SearchProperties( + String titlesSearchType, + String packagesSearchType, + String highlightTag +) { } diff --git a/src/main/java/org/folio/repository/providers/ProviderRepository.java b/src/main/java/org/folio/repository/providers/ProviderRepository.java index 60a5024c3..454ff0ccd 100644 --- a/src/main/java/org/folio/repository/providers/ProviderRepository.java +++ b/src/main/java/org/folio/repository/providers/ProviderRepository.java @@ -11,5 +11,5 @@ public interface ProviderRepository { CompletableFuture delete(String vendorId, UUID credentialsId, String tenantId); - CompletableFuture> findIdsByTagFilter(TagFilter tagFilter, UUID credentialsId, String tenantId); + CompletableFuture> findIdsByTagFilter(TagFilter tagFilter, UUID credentialsId, String tenantId); } diff --git a/src/main/java/org/folio/repository/providers/ProviderRepositoryImpl.java b/src/main/java/org/folio/repository/providers/ProviderRepositoryImpl.java index 81d6119a5..fa1d9ae00 100644 --- a/src/main/java/org/folio/repository/providers/ProviderRepositoryImpl.java +++ b/src/main/java/org/folio/repository/providers/ProviderRepositoryImpl.java @@ -28,6 +28,7 @@ import org.folio.db.exc.translation.DBExceptionTranslator; import org.folio.rest.model.filter.TagFilter; import org.folio.rest.persist.PostgresClient; +import org.folio.rest.util.IdParser; import org.springframework.stereotype.Component; @Log4j2 @@ -76,7 +77,7 @@ public CompletableFuture delete(String vendorId, UUID credentialsId, Strin } @Override - public CompletableFuture> findIdsByTagFilter(TagFilter tagFilter, UUID credentialsId, String tenantId) { + public CompletableFuture> findIdsByTagFilter(TagFilter tagFilter, UUID credentialsId, String tenantId) { List tags = tagFilter.getTags(); if (CollectionUtils.isEmpty(tags)) { return completedFuture(Collections.emptyList()); @@ -99,12 +100,12 @@ public CompletableFuture> findIdsByTagFilter(TagFilter tagFilter, UUI return mapResult(promise.future().recover(excTranslator.translateOrPassBy()), this::mapProviderIds); } - private List mapProviderIds(RowSet resultSet) { + private List mapProviderIds(RowSet resultSet) { return mapItems(resultSet, this::readProviderId); } - private Long readProviderId(Row row) { - return Long.parseLong(row.getString(ID_COLUMN)); + private Integer readProviderId(Row row) { + return IdParser.parseProviderId(row.getString(ID_COLUMN)); } private PostgresClient pgClient(String tenantId) { diff --git a/src/main/java/org/folio/rest/aspect/ValidationErrorHandlerAspect.aj b/src/main/java/org/folio/rest/aspect/ValidationErrorHandlerAspect.aj index a9ceab78b..c2a6e50a8 100644 --- a/src/main/java/org/folio/rest/aspect/ValidationErrorHandlerAspect.aj +++ b/src/main/java/org/folio/rest/aspect/ValidationErrorHandlerAspect.aj @@ -1,39 +1,40 @@ package org.folio.rest.aspect; -import org.folio.holdingsiq.service.exception.RequestValidationException; -import org.folio.rest.annotations.Validate; -import org.folio.rest.exception.InputValidationException; -import org.folio.rest.util.ErrorUtil; - import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; import io.vertx.core.Future; - -import org.aspectj.lang.annotation.SuppressAjWarnings; - -import javax.ws.rs.core.Response; +import io.vertx.core.Handler; import jakarta.validation.ValidationException; +import javax.ws.rs.core.Response; +import org.aspectj.lang.annotation.SuppressAjWarnings; +import org.folio.holdingsiq.service.exception.RequestValidationException; +import org.folio.rest.exception.InputValidationException; +import org.folio.rest.exception.QueryParamsValidationException; +import org.folio.rest.util.ErrorUtil; public aspect ValidationErrorHandlerAspect { - pointcut validatedMethodCall(Handler> asyncResultHandler) : execution(@HandleValidationErrors * *(.., Handler, *)) && args(.., asyncResultHandler, *); + pointcut validatedMethodCall( + Handler> asyncResultHandler): execution(@HandleValidationErrors * *(.., Handler, *)) && args(.., asyncResultHandler, *); @SuppressAjWarnings({"adviceDidNotMatch"}) - void around(Handler asyncResultHandler) : validatedMethodCall(asyncResultHandler) { - try{ + void around(Handler> asyncResultHandler): validatedMethodCall(asyncResultHandler) { + try { proceed(asyncResultHandler); - } - catch (ValidationException | RequestValidationException e){ - asyncResultHandler.handle(Future.succeededFuture(Response.status(400) - .header("Content-Type", "application/vnd.api+json") - .entity(ErrorUtil.createError(e.getMessage())) - .build())); - return; - } - catch (InputValidationException e){ + } catch (ValidationException | RequestValidationException e) { + asyncResultHandler.handle(Future.succeededFuture(Response.status(400) + .header("Content-Type", "application/vnd.api+json") + .entity(ErrorUtil.createError(e.getMessage())) + .build())); + return; + } catch (QueryParamsValidationException e) { + asyncResultHandler.handle(Future.succeededFuture(Response.status(400) + .header("Content-Type", "application/vnd.api+json") + .entity(ErrorUtil.createErrors(e.getMessageDetail())) + .build())); + } catch (InputValidationException e) { asyncResultHandler.handle(Future.succeededFuture(Response.status(422) - .header("Content-Type", "application/vnd.api+json") - .entity(ErrorUtil.createError(e.getMessage(), e.getMessageDetail())) - .build())); + .header("Content-Type", "application/vnd.api+json") + .entity(ErrorUtil.createError(e.getMessage(), e.getMessageDetail())) + .build())); return; } } diff --git a/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java b/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java index 03dbf25d4..d50fc2793 100644 --- a/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java +++ b/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java @@ -63,8 +63,7 @@ public TitleCostPerUse convert(TitleCostPerUseResult source) { .withAttributes(new TitleCostPerUseDataAttributes() .withUsage(usage) .withAnalysis(analysis) - .withParameters(convertParameters(source.getConfiguration())) - ); + .withParameters(convertParameters(source.getConfiguration()))); } private Integer processPlatformUsages(TitleCostPerUseResult source, diff --git a/src/main/java/org/folio/rest/converter/packages/PackageBulkFetchCollectionItemConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageBulkFetchCollectionItemConverter.java index 24c734d78..09dff51e2 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageBulkFetchCollectionItemConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageBulkFetchCollectionItemConverter.java @@ -14,9 +14,9 @@ public class PackageBulkFetchCollectionItemConverter implements Converter { +public class PackageByIdConverter implements Converter { private final Converter packageConverter; public PackageByIdConverter(Converter packageConverter) { @@ -15,7 +15,7 @@ public PackageByIdConverter(Converter packageConverter) } @Override - public Package convert(PackageByIdData packageByIdData) { - return packageConverter.convert(new PackageResult(packageByIdData)); + public Package convert(PackageData packageData) { + return packageConverter.convert(new PackageResult(packageData)); } } diff --git a/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java index 20902e7ab..041d59846 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java @@ -1,13 +1,18 @@ package org.folio.rest.converter.packages; +import static org.folio.common.ListUtils.mapItemsNullable; import static org.folio.rest.converter.common.ConverterConsts.CONTENT_TYPES; import static org.folio.rest.converter.packages.PackageConverterUtils.createEmptyPackageRelationship; import static org.folio.rest.util.RestConstants.PACKAGES_TYPE; +import org.folio.holdingsiq.model.AlternateName; import org.folio.holdingsiq.model.PackageData; +import org.folio.holdingsiq.model.Visibility; import org.folio.rest.jaxrs.model.Coverage; +import org.folio.rest.jaxrs.model.PackageAltName; import org.folio.rest.jaxrs.model.PackageCollectionItem; import org.folio.rest.jaxrs.model.PackageDataAttributes; +import org.folio.rest.jaxrs.model.PackageVisibility; import org.folio.rest.jaxrs.model.VisibilityData; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @@ -20,26 +25,56 @@ public PackageCollectionItem convert(PackageData packageData) { return new PackageCollectionItem() .withId(packageData.getVendorId() + "-" + packageData.getPackageId()) .withType(PACKAGES_TYPE) - .withAttributes(new PackageDataAttributes() - .withContentType(CONTENT_TYPES.get(packageData.getContentType().toLowerCase())) - .withCustomCoverage(convertCustomCoverage(packageData)) - .withIsCustom(packageData.getIsCustom()) - .withIsSelected(packageData.getIsSelected()) - .withName(packageData.getPackageName()) - .withPackageId(packageData.getPackageId()) - .withPackageType(packageData.getPackageType()) - .withProviderId(packageData.getVendorId()) - .withProviderName(packageData.getVendorName()) - .withSelectedCount(packageData.getSelectedCount()) - .withTitleCount(packageData.getTitleCount()) - .withAllowKbToAddTitles(packageData.getAllowEbscoToAddTitles()) - .withVisibilityData(convertVisibilityData(packageData))) + .withAttributes(convertAttributes(packageData)) .withRelationships(createEmptyPackageRelationship()); } + @SuppressWarnings("checkstyle:MethodLength") + private PackageDataAttributes convertAttributes(PackageData packageData) { + return new PackageDataAttributes() + .withAllowKbToAddTitles(packageData.getAllowEbscoToAddTitles()) + .withContentType(CONTENT_TYPES.get(packageData.getContentType().toLowerCase())) + .withCustomAltNames(mapItemsNullable(packageData.getCustomAltNames(), this::convertAltName)) + .withCustomCoverage(convertCustomCoverage(packageData)) + .withCustomDescription(packageData.getCustomDescription()) + .withCustomDisplayName(packageData.getCustomDisplayName()) + .withIsAvailableForSelection(packageData.getAvailableForSelection()) + .withIsCustom(packageData.getIsCustom()) + .withIsFreeAccess(packageData.getPackageFreeAccess()) + .withIsPrimaryPackage(packageData.getIsPrimaryPackage()) + .withIsSelected(packageData.getIsSelected()) + .withManagedAltNames(mapItemsNullable(packageData.getManagedAltNames(), this::convertAltName)) + .withManagedDescription(packageData.getManagedDescription()) + .withName(packageData.getPackageName()) + .withPackageId(packageData.getPackageId()) + .withPackageType(packageData.getPackageType()) + .withProviderId(packageData.getVendorId()) + .withProviderName(packageData.getVendorName()) + .withProxiedUrl(packageData.getProxiedUrl()) + .withSelectedCount(packageData.getSelectedCount()) + .withTitleCount(packageData.getTitleCount()) + .withUrl(packageData.getPackageUrl()) + .withVisibility(mapItemsNullable(packageData.getVisibilityDetails(), this::convertVisibility)) + .withVisibilityData(convertVisibilityData(packageData)); + } + private VisibilityData convertVisibilityData(PackageData packageData) { - return new VisibilityData().withIsHidden(packageData.getVisibilityData().getIsHidden()) - .withReason(packageData.getVisibilityData().getReason().equals("Hidden by EP") ? "Set by system" : ""); + var isHidden = packageData.getVisibilityDetails().stream() + .map(Visibility::hidden) + .reduce(Boolean::logicalOr); + var hiddenByEp = packageData.getVisibilityDetails().stream() + .map(Visibility::reason) + .filter("Hidden by EP"::equals) + .findAny(); + return new VisibilityData().withIsHidden(isHidden.orElse(false)) + .withReason(hiddenByEp.isPresent() ? "Set by system" : ""); + } + + private PackageVisibility convertVisibility(Visibility visibility) { + return new PackageVisibility() + .withCategory(PackageVisibility.Category.fromValue(visibility.category().toUpperCase())) + .withHidden(visibility.hidden()) + .withReason(visibility.reason()); } private Coverage convertCustomCoverage(PackageData packageData) { @@ -47,4 +82,10 @@ private Coverage convertCustomCoverage(PackageData packageData) { .withBeginCoverage(packageData.getCustomCoverage().getBeginCoverage()) .withEndCoverage(packageData.getCustomCoverage().getEndCoverage()); } + + private PackageAltName convertAltName(AlternateName alternateName) { + return new PackageAltName() + .withId(alternateName.id() == null ? null : alternateName.id()) + .withAltName(alternateName.altName()); + } } diff --git a/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java index b60a11a01..628ede9b3 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageCollectionResultConverter.java @@ -55,9 +55,6 @@ private List getTagsById(List packages, PackageId packageId) } private PackageId createPackageId(PackageData packageData) { - return PackageId.builder() - .providerIdPart(packageData.getVendorId()) - .packageIdPart(packageData.getPackageId()) - .build(); + return new PackageId(packageData.getVendorId(), packageData.getPackageId()); } } diff --git a/src/main/java/org/folio/rest/converter/packages/PackageConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageConverter.java index 61101488b..251f9ff1c 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageConverter.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Objects; -import org.folio.holdingsiq.model.PackageByIdData; import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.model.TokenInfo; @@ -51,37 +50,37 @@ public PackageConverter(Converter packageCol @Override public Package convert(PackageResult result) { - PackageByIdData packageByIdData = result.getPackageData(); + PackageData packageData = result.getPackageData(); - Package packageData = new Package() - .withData(packageCollectionItemConverter.convert(packageByIdData)) + Package packageResult = new Package() + .withData(packageCollectionItemConverter.convert(packageData)) .withJsonapi(RestConstants.JSONAPI); - packageData.getData() + packageResult.getData() .withRelationships(createEmptyPackageRelationship()) .withType(PACKAGES_TYPE) .getAttributes() - .withProxy(convertToProxy(packageByIdData.getProxy())) - .withPackageToken(tokenInfoConverter.convert(packageByIdData.getPackageToken())) + .withProxy(convertToProxy(packageData.getProxy())) + .withPackageToken(tokenInfoConverter.convert(packageData.getPackageToken())) .withTags(result.getTags()); - addTitlesRelationship(result, packageData, packageByIdData); - addProviderRelationship(result, packageData); - addAccessTypeRelationship(result, packageData); - return packageData; + addTitlesRelationship(result, packageResult, packageData); + addProviderRelationship(result, packageResult); + addAccessTypeRelationship(result, packageResult); + return packageResult; } - private void addTitlesRelationship(PackageResult result, Package packageData, PackageByIdData packageByIdData) { + private void addTitlesRelationship(PackageResult result, Package packageDto, PackageData packageData) { Titles titles = result.getTitles(); if (titles != null) { - packageData.getData() + packageDto.getData() .withRelationships(new PackageRelationship() .withResources(new HasManyRelationship() .withMeta(new MetaDataIncluded() .withIncluded(true)) - .withData(convertResourcesRelationship(packageByIdData, titles)))); + .withData(convertResourcesRelationship(packageData, titles)))); - packageData + packageDto .getIncluded() .addAll(Objects.requireNonNull(resourcesConverter.convert(titles)).getData()); } @@ -119,10 +118,10 @@ private void addAccessTypeRelationship(PackageResult result, Package packageData return proxy != null ? new Proxy().withId(proxy.getId()).withInherited(proxy.getInherited()) : null; } - private List convertResourcesRelationship(PackageByIdData packageByIdData, Titles titles) { + private List convertResourcesRelationship(PackageData packageData, Titles titles) { return mapItems(titles.getTitleList(), title -> new RelationshipData() - .withId(packageByIdData.getVendorId() + "-" + packageByIdData.getPackageId() + "-" + title.getTitleId()) + .withId(packageData.getVendorId() + "-" + packageData.getPackageId() + "-" + title.getTitleId()) .withType(RESOURCES_TYPE)); } } diff --git a/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java index 5d78b916e..9b01a2f86 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java @@ -1,32 +1,38 @@ package org.folio.rest.converter.packages; +import static org.folio.common.ListUtils.mapItems; import static org.folio.rest.converter.packages.PackageConverterUtils.CONTENT_TYPE_TO_RMAPI_CODE; +import java.util.Arrays; +import org.folio.holdingsiq.model.AlternateName; import org.folio.holdingsiq.model.CoverageDates; import org.folio.holdingsiq.model.PackagePut; +import org.folio.holdingsiq.model.Proxy; import org.folio.holdingsiq.model.TokenInfo; +import org.folio.holdingsiq.model.Visibility; import org.folio.rest.jaxrs.model.PackagePutDataAttributes; import org.folio.rest.jaxrs.model.PackagePutRequest; +import org.folio.rest.jaxrs.model.PackageVisibility; import org.springframework.stereotype.Component; @Component public class PackageRequestConverter { public PackagePut convertToRmApiCustomPackagePutRequest(PackagePutRequest request) { - PackagePutDataAttributes attributes = request.getData().getAttributes(); - PackagePut.PackagePutBuilder builder = convertCommonAttributesToPackagePutRequest(attributes); + var attributes = request.getData().getAttributes(); + var builder = convertCommonAttributesToPackagePutRequest(attributes); builder.packageName(attributes.getName()); - Integer contentType = CONTENT_TYPE_TO_RMAPI_CODE.get(attributes.getContentType()); + var contentType = CONTENT_TYPE_TO_RMAPI_CODE.get(attributes.getContentType()); builder.contentType(contentType != null ? contentType : 6); return builder.build(); } public PackagePut convertToRmApiPackagePutRequest(PackagePutRequest request) { - PackagePutDataAttributes attributes = request.getData().getAttributes(); - PackagePut.PackagePutBuilder builder = convertCommonAttributesToPackagePutRequest(attributes); + var attributes = request.getData().getAttributes(); + var builder = convertCommonAttributesToPackagePutRequest(attributes); builder.allowEbscoToAddTitles(attributes.getAllowKbToAddTitles()); if (attributes.getPackageToken() != null) { - TokenInfo tokenInfo = TokenInfo.builder() + var tokenInfo = TokenInfo.builder() .value(attributes.getPackageToken().getValue()) .build(); builder.packageToken(tokenInfo); @@ -34,14 +40,15 @@ public PackagePut convertToRmApiPackagePutRequest(PackagePutRequest request) { return builder.build(); } + @SuppressWarnings("checkstyle:MethodLength") private PackagePut.PackagePutBuilder convertCommonAttributesToPackagePutRequest(PackagePutDataAttributes attributes) { - PackagePut.PackagePutBuilder builder = PackagePut.builder(); + var builder = PackagePut.builder(); builder.isSelected(attributes.getIsSelected()); builder.isFullPackage(attributes.getIsFullPackage()); if (attributes.getProxy() != null) { - org.folio.holdingsiq.model.Proxy proxy = org.folio.holdingsiq.model.Proxy.builder() + var proxy = Proxy.builder() .id(attributes.getProxy().getId()) // RM API gives an error when we pass inherited as true along with updated proxy value // Hard code it to false; it should not affect the state of inherited that RM API maintains @@ -50,18 +57,35 @@ private PackagePut.PackagePutBuilder convertCommonAttributesToPackagePutRequest( builder.proxy(proxy); } - if (attributes.getVisibilityData() != null) { - builder.isHidden(attributes.getVisibilityData().getIsHidden()); - } - if (attributes.getCustomCoverage() != null) { - CoverageDates coverageDates = CoverageDates.builder() + var coverageDates = CoverageDates.builder() .beginCoverage(attributes.getCustomCoverage().getBeginCoverage()) .endCoverage(attributes.getCustomCoverage().getEndCoverage()) .build(); builder.customCoverage(coverageDates); } + if (attributes.getCustomAltNames() != null) { + builder.customAltNames(mapItems(attributes.getCustomAltNames(), + packageAltName -> new AlternateName(packageAltName.getId(), packageAltName.getAltName()))); + } + + builder.customDescription(attributes.getCustomDescription()); + builder.customDisplayName(attributes.getCustomDisplayName()); + builder.packageFreeAccess(attributes.getIsFreeAccess()); + builder.packageUrl(attributes.getUrl()); + + var visibilityData = attributes.getVisibilityData(); + if (visibilityData == null || visibilityData.getIsHidden() == null) { + builder.visibilityDetails(mapItems(attributes.getVisibility(), + pv -> new Visibility(pv.getCategory().value(), pv.getHidden(), pv.getReason()))); + } else { + var visibilities = Arrays.stream(PackageVisibility.Category.values()) + .map(category -> new Visibility(category.value(), visibilityData.getIsHidden(), visibilityData.getReason())) + .toList(); + builder.visibilityDetails(visibilities); + } + return builder; } } diff --git a/src/main/java/org/folio/rest/converter/resources/ResourceCollectionResultConverter.java b/src/main/java/org/folio/rest/converter/resources/ResourceCollectionResultConverter.java index bd04bcebc..d0b1b6635 100644 --- a/src/main/java/org/folio/rest/converter/resources/ResourceCollectionResultConverter.java +++ b/src/main/java/org/folio/rest/converter/resources/ResourceCollectionResultConverter.java @@ -70,17 +70,12 @@ private ResourceCollectionItem mapResourceCollectionItem(List resour } private ResourceId createResourceId(Title title) { - return ResourceId.builder() - .providerIdPart(title.getCustomerResourcesList().getFirst().getVendorId()) - .packageIdPart(title.getCustomerResourcesList().getFirst().getPackageId()) - .titleIdPart(title.getTitleId()).build(); + return new ResourceId(title.getCustomerResourcesList().getFirst().getVendorId(), + title.getCustomerResourcesList().getFirst().getPackageId(), + title.getTitleId()); } private ResourceId createResourceId(DbHoldingInfo holding) { - return ResourceId.builder() - .providerIdPart(holding.getVendorId()) - .packageIdPart(holding.getPackageId()) - .titleIdPart(holding.getTitleId()) - .build(); + return new ResourceId(holding.getVendorId(), holding.getPackageId(), holding.getTitleId()); } } diff --git a/src/main/java/org/folio/rest/converter/resources/ResourceResultConverter.java b/src/main/java/org/folio/rest/converter/resources/ResourceResultConverter.java index 295018d7e..5c141eb72 100644 --- a/src/main/java/org/folio/rest/converter/resources/ResourceResultConverter.java +++ b/src/main/java/org/folio/rest/converter/resources/ResourceResultConverter.java @@ -12,7 +12,7 @@ import java.util.List; import java.util.function.Function; import org.folio.holdingsiq.model.CustomerResources; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.VendorById; import org.folio.rest.jaxrs.model.AccessType; import org.folio.rest.jaxrs.model.HasOneRelationship; @@ -44,12 +44,12 @@ public class ResourceResultConverter implements Converter vendorConverter; @Autowired - private Converter packageByIdConverter; + private Converter packageByIdConverter; @Override public List convert(ResourceResult resourceResult) { var rmapiTitle = resourceResult.getTitle(); - PackageByIdData packageData = resourceResult.getPackageData(); + PackageData packageData = resourceResult.getPackageData(); VendorById vendor = resourceResult.getVendor(); AccessType accessType = resourceResult.getAccessType(); boolean includeTitle = resourceResult.isIncludeTitle(); @@ -63,7 +63,7 @@ public List convert(ResourceResult resourceResult) { private Function convertToResource(org.folio.holdingsiq.model.Title rmapiTitle, boolean titleHasSelectedResources, boolean includeTitle, - VendorById vendor, PackageByIdData packageData, + VendorById vendor, PackageData packageData, AccessType accessType) { return resource -> { Resource resultResource = new Resource() @@ -83,7 +83,7 @@ private Function convertToResource(org.folio.holdin } private void includedResources(org.folio.holdingsiq.model.Title rmapiTitle, boolean includeTitle, - @Nullable VendorById vendor, @Nullable PackageByIdData packageData, + @Nullable VendorById vendor, @Nullable PackageData packageData, @Nullable AccessType accessType, Resource resultResource) { resultResource.setIncluded(new ArrayList<>()); if (includeTitle) { @@ -112,7 +112,7 @@ private void includeAccessType(AccessType accessType, Resource resultResource) { .withIncluded(true))); } - private void includePackage(PackageByIdData packageData, Resource resultResource) { + private void includePackage(PackageData packageData, Resource resultResource) { resultResource.getIncluded().add(requireNonNull(packageByIdConverter.convert(packageData)).getData()); resultResource.getData() .getRelationships() diff --git a/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java b/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java new file mode 100644 index 000000000..086f824a0 --- /dev/null +++ b/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java @@ -0,0 +1,21 @@ +package org.folio.rest.exception; + +import java.io.Serial; +import java.util.List; + +public class QueryParamsValidationException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + private final List messageDetail; + + public QueryParamsValidationException(List messageDetail) { + super("Query params validation failed."); + this.messageDetail = messageDetail; + } + + public List getMessageDetail() { + return messageDetail; + } +} diff --git a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java index acfe81b7b..9a6dd172e 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -29,12 +29,12 @@ import org.folio.cache.VertxCache; import org.folio.config.cache.VendorIdCacheKey; import org.folio.holdingsiq.model.CustomerResources; -import org.folio.holdingsiq.model.OkapiData; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.PackageId; import org.folio.holdingsiq.model.PackagePost; import org.folio.holdingsiq.model.PackagePut; import org.folio.holdingsiq.model.Packages; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; import org.folio.properties.common.SearchProperties; @@ -64,7 +64,10 @@ import org.folio.rest.jaxrs.model.ResourceCollection; import org.folio.rest.jaxrs.model.Tags; import org.folio.rest.jaxrs.resource.EholdingsPackages; -import org.folio.rest.model.filter.Filter; +import org.folio.rest.model.filter.AccessTypeFilter; +import org.folio.rest.model.filter.PackageRecordFilter; +import org.folio.rest.model.filter.ResourceFilter; +import org.folio.rest.model.filter.TagFilter; import org.folio.rest.util.ErrorHandler; import org.folio.rest.util.ErrorUtil; import org.folio.rest.util.template.RmApiTemplate; @@ -113,7 +116,7 @@ public class EholdingsPackagesImpl implements EholdingsPackages { private RmApiTemplateFactory templateFactory; @Autowired @Qualifier("vendorIdCache") - private VertxCache vendorIdCache; + private VertxCache vendorIdCache; @Autowired private TagRepository tagRepository; @Autowired @@ -138,29 +141,43 @@ public EholdingsPackagesImpl() { SpringContextUtil.autowireDependencies(this, Vertx.currentContext()); } + @SuppressWarnings("checkstyle:MethodLength") @Override @Validate @HandleValidationErrors - public void getEholdingsPackages(String filterCustom, String q, String filterSelected, String filterType, - List filterTags, List filterAccessType, String sort, int page, - int count, - Map okapiHeaders, Handler> asyncResultHandler, - Context vertxContext) { - - var filter = Filter.getSortableFilter(prepareFilterForPackage(filterCustom, q, filterSelected, filterType, - filterTags, filterAccessType), sort, page, count); + public void getEholdingsPackages(String filterCustom, String q, String queryField, String queryType, + boolean highlight, String filterSelected, String filterType, String filterVisibility, + String filterFreeAccess, List filterTags, List filterAccessType, + String sort, int page, int count, Map okapiHeaders, + Handler> asyncResultHandler, Context vertxContext) { + var filter = PackageRecordFilter.builder() + .query(q) + .queryField(queryField) + .queryType(queryType) + .highlight(highlight) + .filterCustom(filterCustom) + .filterSelected(filterSelected) + .filterType(filterType) + .filterVisibility(filterVisibility) + .filterFreeAccess(filterFreeAccess) + .filterTags(filterTags) + .filterAccessType(filterAccessType) + .sort(sort) + .page(page) + .count(count) + .build(); var template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); if (filter.isTagsFilter()) { template.requestAction( - context -> filteredEntitiesLoader.fetchPackagesByTagFilter(filter.createTagFilter(), context)); + context -> filteredEntitiesLoader.fetchPackagesByTagFilter(TagFilter.from(filter), context)); } else if (filter.isAccessTypeFilter()) { template.requestAction(context -> filteredEntitiesLoader - .fetchPackagesByAccessTypeFilter(filter.createAccessTypeFilter(), context)); + .fetchPackagesByAccessTypeFilter(AccessTypeFilter.from(filter), context)); } else { template .requestAction(context -> { - if (Boolean.TRUE.equals(filter.getFilterCustom())) { + if (Boolean.TRUE.equals(filter.resolveFilterCustom())) { return getCustomProviderId(context) .thenCompose(providerId -> retrievePackages(providerId, filter, context)); } else { @@ -226,12 +243,13 @@ public void putEholdingsPackagesByPackageId(String packageId, String contentType Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { PackageId parsedPackageId = parsePackageId(packageId); + var packageIdPart = parsedPackageId.packageIdPart(); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) - .requestAction(context -> context.getPackagesService().retrievePackage(parsedPackageId) - .thenCompose(packageByIdData -> fetchAccessType(entity, context) - .thenCompose(accessType -> processUpdateRequest(entity, packageByIdData, context) + .requestAction(context -> context.getPackagesService().retrievePackage(packageIdPart) + .thenCompose(packageData -> fetchAccessType(entity, context) + .thenCompose(accessType -> processUpdateRequest(entity, packageData, context) .thenCompose(voidEntity -> { - CompletableFuture future = context.getPackagesService().retrievePackage(parsedPackageId); + CompletableFuture future = context.getPackagesService().retrievePackage(packageIdPart); return handleDeletedPackage(future, parsedPackageId, context); }) .thenApply(packageById -> new PackageResult(packageById, null, null)) @@ -250,19 +268,21 @@ public void deleteEholdingsPackagesByPackageId(String packageId, Map> asyncResultHandler, Context vertxContext) { PackageId parsedPackageId = parsePackageId(packageId); + var packageIdPart = parsedPackageId.packageIdPart(); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) .requestAction(context -> - context.getPackagesService().retrievePackage(parsedPackageId) + context.getPackagesService().retrievePackage(packageIdPart) .thenCompose(packageData -> { if (BooleanUtils.isNotTrue(packageData.getIsCustom())) { throw new InputValidationException(INVALID_PACKAGE_TITLE, INVALID_PACKAGE_DETAILS); } - return context.getPackagesService().deletePackage(parsedPackageId) + return context.getPackagesService().deletePackage(packageIdPart) .thenCompose(v -> deleteAssignedResources(parsedPackageId, context)); })) .execute(); } + @SuppressWarnings("checkstyle:MethodLength") @Override @Validate @HandleValidationErrors @@ -275,17 +295,29 @@ public void getEholdingsPackagesResourcesByPackageId(String packageId, List> asyncResultHandler, Context vertxContext) { - var filter = Filter.getSortableFilter(prepareFilterForResource(packageId, filterTags, filterAccessType, - filterSelected, filterType, filterName, filterIsxn, filterSubject, filterPublisher), sort, page, count); + var filter = ResourceFilter.builder() + .packageId(packageId) + .filterTags(filterTags) + .filterAccessType(filterAccessType) + .filterSelected(filterSelected) + .filterType(filterType) + .filterName(filterName) + .filterIsxn(filterIsxn) + .filterSubject(filterSubject) + .filterPublisher(filterPublisher) + .sort(sort) + .page(page) + .count(count) + .build(); RmApiTemplate template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); if (filter.isTagsFilter()) { template.requestAction( - context -> filteredEntitiesLoader.fetchResourcesByTagFilter(filter.createTagFilter(), context)); + context -> filteredEntitiesLoader.fetchResourcesByTagFilter(TagFilter.from(filter), context)); } else if (filter.isAccessTypeFilter()) { template.requestAction( - context -> filteredEntitiesLoader.fetchResourcesByAccessTypeFilter(filter.createAccessTypeFilter(), context)); + context -> filteredEntitiesLoader.fetchResourcesByAccessTypeFilter(AccessTypeFilter.from(filter), context)); } else { template.requestAction(retrievePackageTitles(filter)); } @@ -298,17 +330,17 @@ public void getEholdingsPackagesResourcesByPackageId(String packageId, List okapiHeaders, + Map headers, Handler> asyncResultHandler, Context vertxContext) { - userKbCredentialsService.findByUser(okapiHeaders) + userKbCredentialsService.findByUser(headers) .thenCompose(creds -> { packageTagsPutBodyValidator.validate(entity); PackageTagsDataAttributes attributes = entity.getData().getAttributes(); return updateTags(attributes.getTags(), createDbPackage(packageId, UUID.fromString(creds.getId()), attributes), - new OkapiData(okapiHeaders).getTenant()) + new RequestContext(headers).getTenant()) .thenAccept(o2 -> asyncResultHandler .handle( @@ -334,53 +366,25 @@ public void postEholdingsPackagesBulkFetch(String contentType, PackagePostBulkFe .executeWithResult(PackageBulkFetchCollection.class); } - private Function> retrievePackageTitles(Filter filter) { + private Function> retrievePackageTitles(ResourceFilter filter) { return context -> { - var pkgId = filter.getPackageId(); + var pkgId = filter.parsePackageId(); return context.getTitlesService() - .retrieveTitles(pkgId.getProviderIdPart(), pkgId.getPackageIdPart(), filter.createFilterQuery(), - searchProperties.titlesSearchType(), filter.getSort(), filter.getPage(), filter.getCount()) + .retrieveTitles(pkgId.providerIdPart(), pkgId.packageIdPart(), filter.createFilterQuery(), + searchProperties.titlesSearchType(), filter.resolveSort(), filter.getPage(), filter.getCount()) .thenApply(titles -> titleCollectionConverter.convert(titles)) .thenCompose(loadResourceTags(context)) .thenCompose(loadResourceAccessTypes(context)); }; } - private CompletableFuture retrievePackages(Long providerId, Filter filter, RmApiTemplateContext context) { - return context.getPackagesService() - .retrievePackages(filter.getFilterSelected(), filter.getFilterType(), searchProperties.packagesSearchType(), - providerId, filter.getQuery(), filter.getPage(), filter.getCount(), filter.getSort()); - } - - @SuppressWarnings("java:S107") - private Filter.FilterBuilder prepareFilterForResource(String packageId, List filterTags, - List filterAccessType, String filterSelected, - String filterType, String filterName, String filterIsxn, - String filterSubject, String filterPublisher) { - return Filter.builder() - .recordType(RecordType.RESOURCE) - .filterTags(filterTags) - .packageId(packageId) - .filterAccessType(filterAccessType) - .filterSelected(filterSelected) - .filterType(filterType) - .filterName(filterName) - .filterIsxn(filterIsxn) - .filterSubject(filterSubject) - .filterPublisher(filterPublisher); - } - - private Filter.FilterBuilder prepareFilterForPackage(String filterCustom, String q, String filterSelected, - String filterType, List filterTags, - List filterAccessType) { - return Filter.builder() - .recordType(RecordType.PACKAGE) - .query(q) - .filterTags(filterTags) - .filterCustom(filterCustom) - .filterAccessType(filterAccessType) - .filterSelected(filterSelected) - .filterType(filterType); + private CompletableFuture retrievePackages(Integer providerId, PackageRecordFilter filter, + RmApiTemplateContext context) { + var packageFilter = filter.toClientFilter(searchProperties); + var pageable = filter.toPageable(); + return providerId == null + ? context.getPackagesService().retrievePackages(packageFilter, pageable) + : context.getPackagesService().retrievePackages(providerId, packageFilter, pageable); } private CompletableFuture updateAccessTypeMapping(AccessType accessType, @@ -397,17 +401,17 @@ private CompletableFuture updateAccessTypeMapping(AccessType acce private CompletableFuture updateRecordMapping(AccessType accessType, String recordId, RmApiTemplateContext context) { return accessTypeMappingsService.update(accessType, recordId, RecordType.PACKAGE, context.getCredentialsId(), - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } private CompletableFuture fetchAccessType(PackagePutRequest entity, RmApiTemplateContext context) { String accessTypeId = entity.getData().getAttributes().getAccessTypeId(); if (accessTypeId == null) { - return CompletableFuture.completedFuture(null); + return completedFuture(null); } else { return accessTypesService.findByCredentialsAndAccessTypeId(context.getCredentialsId(), accessTypeId, false, - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } } @@ -439,7 +443,7 @@ private Function> return titleCollection -> { Map resourceIdToTitle = mapResourceIdToTitleResult(titleCollection); - return tagRepository.findPerRecord(context.getOkapiData().getTenant(), + return tagRepository.findPerRecord(context.getRequestContext().getTenant(), new ArrayList<>(resourceIdToTitle.keySet()), RecordType.RESOURCE) .thenApply(tagMap -> { @@ -461,7 +465,7 @@ private Function> return titleCollection -> { Map resourceIdToAccessType = mapResourceIdToTitleResult(titleCollection); String credentialsId = context.getCredentialsId(); - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); return accessTypesService.findPerRecord(credentialsId, new ArrayList<>(resourceIdToAccessType.keySet()), RecordType.RESOURCE, tenant) .thenApply(accessTypeMap -> { @@ -490,12 +494,12 @@ private String getResourceId(TitleResult titleResult) { return resource.getVendorId() + "-" + resource.getPackageId() + "-" + resource.getTitleId(); } - private CompletableFuture getCustomProviderId(RmApiTemplateContext context) { + private CompletableFuture getCustomProviderId(RmApiTemplateContext context) { VendorIdCacheKey cacheKey = VendorIdCacheKey.builder() - .tenant(context.getOkapiData().getTenant()) + .tenant(context.getRequestContext().getTenant()) .rmapiConfiguration(context.getConfiguration()) .build(); - Long cachedId = vendorIdCache.getValue(cacheKey); + var cachedId = vendorIdCache.getValue(cacheKey); if (cachedId != null) { return completedFuture(cachedId); } else { @@ -509,7 +513,7 @@ private CompletableFuture getCustomProviderId(RmApiTemplateContext context private CompletableFuture deleteTags(PackageId packageId, RmApiTemplateContext context) { UUID credentialsId = toUUID(context.getCredentialsId()); - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); return packageRepository.delete(packageId, credentialsId, tenant) .thenCompose(o -> tagRepository.deleteRecordTags(tenant, packageIdToString(packageId), RecordType.PACKAGE)) @@ -535,7 +539,7 @@ private CompletableFuture updateStoredPackage(Tags tags, DbPackage pkg, St return packageRepository.delete(pkg.getId(), pkg.getCredentialsId(), tenant); } - private CompletableFuture processUpdateRequest(PackagePutRequest entity, PackageByIdData originalPackage, + private CompletableFuture processUpdateRequest(PackagePutRequest entity, PackageData originalPackage, RmApiTemplateContext context) { Boolean isEntityCustom = entity.getData().getAttributes().getIsCustom(); validateIsCustomMatch(originalPackage.getIsCustom(), isEntityCustom); @@ -549,7 +553,7 @@ private CompletableFuture processUpdateRequest(PackagePutRequest entity, P packagePutBody = converter.convertToRmApiPackagePutRequest(entity); } return context.getPackagesService() - .updatePackage(parsePackageId(originalPackage.getFullPackageId()), packagePutBody); + .updatePackage(originalPackage.getPackageId(), packagePutBody); } private void validateIsCustomMatch(Boolean isOriginalCustom, Boolean isUpdatableCustom) { @@ -565,8 +569,8 @@ private void validateIsCustomMatch(Boolean isOriginalCustom, Boolean isUpdatable * * @return future with initial result, or exceptionally completed future if deletion of tags failed */ - private CompletableFuture handleDeletedPackage(CompletableFuture future, - PackageId packageId, RmApiTemplateContext context) { + private CompletableFuture handleDeletedPackage(CompletableFuture future, + PackageId packageId, RmApiTemplateContext context) { CompletableFuture deleteFuture = new CompletableFuture<>(); return future.whenComplete((packageById, e) -> { if (e instanceof ResourceNotFoundException) { diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index 0a0e02a83..b6538ee62 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -21,11 +21,12 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Function; import javax.ws.rs.core.Response; -import org.folio.holdingsiq.model.OkapiData; import org.folio.holdingsiq.model.Packages; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.VendorById; import org.folio.holdingsiq.model.VendorPut; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; +import org.folio.properties.common.SearchProperties; import org.folio.repository.RecordKey; import org.folio.repository.RecordType; import org.folio.repository.packages.PackageRepository; @@ -46,7 +47,10 @@ import org.folio.rest.jaxrs.model.ProviderTagsPutRequest; import org.folio.rest.jaxrs.model.Tags; import org.folio.rest.jaxrs.resource.EholdingsProviders; -import org.folio.rest.model.filter.Filter; +import org.folio.rest.model.filter.AccessTypeFilter; +import org.folio.rest.model.filter.PackageRecordFilter; +import org.folio.rest.model.filter.ProviderFilter; +import org.folio.rest.model.filter.TagFilter; import org.folio.rest.util.ErrorHandler; import org.folio.rest.util.ErrorUtil; import org.folio.rest.util.template.RmApiTemplate; @@ -62,7 +66,6 @@ import org.folio.spring.SpringContextUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; import org.springframework.core.convert.converter.Converter; @SuppressWarnings("java:S6813") @@ -91,8 +94,8 @@ public class EholdingsProvidersImpl implements EholdingsProviders { @Autowired @Qualifier("securedUserCredentialsService") private UserKbCredentialsService userKbCredentialsService; - @Value("${kb.ebsco.search-type.packages}") - private String packagesSearchType; + @Autowired + private SearchProperties searchProperties; public EholdingsProvidersImpl() { SpringContextUtil.autowireDependencies(this, Vertx.currentContext()); @@ -106,8 +109,7 @@ public void getEholdingsProviders(String q, List filterTags, String sort Handler> asyncResultHandler, Context vertxContext) { RmApiTemplate template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); - Filter filter = Filter.builder() - .recordType(RecordType.PROVIDER) + var filter = ProviderFilter.builder() .query(q) .filterTags(filterTags) .sort(sort) @@ -116,25 +118,25 @@ public void getEholdingsProviders(String q, List filterTags, String sort .build(); if (filter.isTagsFilter()) { template.requestAction( - context -> filteredEntitiesLoader.fetchProvidersByTagFilter(filter.createTagFilter(), context)); + context -> filteredEntitiesLoader.fetchProvidersByTagFilter(TagFilter.from(filter), context)); } else { template .requestAction(context -> - context.getProvidersService().retrieveProviders(q, page, count, filter.getSort())); + context.getProvidersService().retrieveProviders(q, page, count, filter.resolveSort())); } template.executeWithResult(ProviderCollection.class); } @Override + @Validate @HandleValidationErrors public void getEholdingsProvidersByProviderId(String providerId, String include, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - long providerIdLong = parseProviderId(providerId); - + var parseProviderId = parseProviderId(providerId); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) .requestAction(context -> - context.getProvidersService().retrieveProvider(providerIdLong, include) + context.getProvidersService().retrieveProvider(parseProviderId, include) .thenCompose(result -> loadTags(result, context)) ) .addErrorMapper(ResourceNotFoundException.class, exception -> @@ -144,38 +146,40 @@ public void getEholdingsProvidersByProviderId(String providerId, String include, } @Override + @Validate @HandleValidationErrors public void putEholdingsProvidersByProviderId(String providerId, String contentType, ProviderPutRequest entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - long providerIdLong = parseProviderId(providerId); bodyValidator.validate(entity); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) .requestAction(context -> - processUpdateRequest(entity, providerIdLong, context) + processUpdateRequest(entity, parseProviderId(providerId), context) .thenApply(result -> new VendorResult(result, null))) .addErrorMapper(InputValidationException.class, error422InputValidationMapper()) .executeWithResult(Provider.class); } @Override + @Validate + @HandleValidationErrors public void putEholdingsProvidersTagsByProviderId(String providerId, String contentType, ProviderTagsPutRequest entity, - Map okapiHeaders, + Map headers, Handler> asyncResultHandler, Context vertxContext) { final Tags tags = entity.getData().getAttributes().getTags(); - userKbCredentialsService.findByUser(okapiHeaders) + userKbCredentialsService.findByUser(headers) .thenCompose(creds -> { ProviderTagsDataAttributes attributes = entity.getData().getAttributes(); providerTagsPutBodyValidator.validate(entity, attributes); return updateTags( createDbProvider(providerId, UUID.fromString(creds.getId()), entity.getData().getAttributes()), - tags, new OkapiData(okapiHeaders).getTenant()) + tags, new RequestContext(headers).getTenant()) .thenAccept(ob -> asyncResultHandler.handle( Future.succeededFuture(PutEholdingsProvidersTagsByProviderIdResponse.respond200WithApplicationVndApiJson( convertToProviderTags(attributes) @@ -189,28 +193,45 @@ tags, new OkapiData(okapiHeaders).getTenant()) }); } + @SuppressWarnings("checkstyle:MethodLength") @Override @Validate @HandleValidationErrors - public void getEholdingsProvidersPackagesByProviderId(String providerId, String q, List filterTags, + public void getEholdingsProvidersPackagesByProviderId(String providerId, String q, String queryField, + String queryType, boolean highlight, List filterTags, List filterAccessType, String filterSelected, - String filterType, String sort, int page, int count, + String filterType, String filterVisibility, String filterAccess, + String sort, int page, int count, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - var filter = Filter.getSortableFilter(getPackageFilter(providerId, q, filterTags, filterAccessType, filterSelected, - filterType), sort, page, count); + var parsedProviderId = parseProviderId(providerId); + var filter = PackageRecordFilter.builder() + .query(q) + .queryField(queryField) + .queryType(queryType) + .filterTags(filterTags) + .providerId(providerId) + .filterAccessType(filterAccessType) + .filterSelected(filterSelected) + .filterType(filterType) + .filterVisibility(filterVisibility) + .filterFreeAccess(filterAccess) + .sort(sort) + .page(page) + .count(count) + .build(); RmApiTemplate template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); if (filter.isTagsFilter()) { template.requestAction( - context -> filteredEntitiesLoader.fetchPackagesByTagFilter(filter.createTagFilter(), context)); + context -> filteredEntitiesLoader.fetchPackagesByTagFilter(TagFilter.from(filter), context)); } else if (filter.isAccessTypeFilter()) { template.requestAction(context -> filteredEntitiesLoader - .fetchPackagesByAccessTypeFilter(filter.createAccessTypeFilter(), context) + .fetchPackagesByAccessTypeFilter(AccessTypeFilter.from(filter), context) .thenApply(packages -> new PackageCollectionResult(packages, emptyList()))); } else { - template.requestAction(retrieveFilteredPackages(filter)); + template.requestAction(retrieveFilteredPackages(parsedProviderId, filter)); } template .addErrorMapper(ResourceNotFoundException.class, exception -> @@ -219,24 +240,13 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String .executeWithResult(PackageCollection.class); } - private Filter.FilterBuilder getPackageFilter(String providerId, String q, List filterTags, - List filterAccessType, - String filterSelected, String filterType) { - return Filter.builder() - .recordType(RecordType.PACKAGE) - .query(q) - .filterTags(filterTags) - .providerId(providerId) - .filterAccessType(filterAccessType) - .filterSelected(filterSelected) - .filterType(filterType); - } - - private Function> retrieveFilteredPackages(Filter filter) { + private Function> retrieveFilteredPackages(int providerId, + PackageRecordFilter filter) { + var packageFilter = filter.toClientFilter(searchProperties); + var pageable = filter.toPageable(); return context -> context.getPackagesService() - .retrievePackages(filter.getFilterSelected(), filter.getFilterType(), packagesSearchType, - filter.getProviderId(), filter.getQuery(), filter.getPage(), filter.getCount(), filter.getSort()) + .retrievePackages(providerId, packageFilter, pageable) .thenCompose(packages -> loadTags(packages, context)); } @@ -250,7 +260,7 @@ private CompletableFuture loadTags(VendorResult result, RmApiTempl private CompletableFuture loadTags(Packages packages, RmApiTemplateContext context) { UUID credentialsId = toUUID(context.getCredentialsId()); - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); return packageRepository.findByIds(getPackageIds(packages), credentialsId, tenant) .thenApply(dbPackages -> new PackageCollectionResult(packages, dbPackages)); } @@ -290,13 +300,13 @@ private CompletableFuture updateStoredProvider(DbProvider provider, Tags t return providerRepository.delete(provider.getId(), provider.getCredentialsId(), tenant); } - private CompletableFuture processUpdateRequest(ProviderPutRequest request, long providerIdLong, + private CompletableFuture processUpdateRequest(ProviderPutRequest request, int providerId, RmApiTemplateContext context) { if (!providerCanBeUpdated(request)) { //Return current state of provider without updating it - return context.getProvidersService().retrieveProvider(providerIdLong); + return context.getProvidersService().retrieveProvider(providerId); } - return context.getProvidersService().updateProvider(providerIdLong, putRequestConverter.convert(request)); + return context.getProvidersService().updateProvider(providerId, putRequestConverter.convert(request)); } private boolean providerCanBeUpdated(ProviderPutRequest request) { diff --git a/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java index bd9be22f8..16fa2cd8c 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java @@ -1,8 +1,7 @@ package org.folio.rest.impl; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.protocol.HTTP.CONTENT_TYPE; +import static org.folio.HttpStatus.SC_NOT_FOUND; import static org.folio.common.ListUtils.parseByComma; import static org.folio.rest.util.ErrorUtil.createError; import static org.folio.rest.util.ExceptionMappers.error400NotFoundMapper; @@ -32,12 +31,13 @@ import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Response; import org.apache.commons.lang3.BooleanUtils; +import org.folio.HttpHeaders; import org.folio.db.RowSetUtils; import org.folio.holdingsiq.model.CustomerResources; import org.folio.holdingsiq.model.FilterQuery; -import org.folio.holdingsiq.model.OkapiData; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.PackageId; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.ResourceId; import org.folio.holdingsiq.model.ResourcePut; import org.folio.holdingsiq.model.ResourceSelectedPayload; @@ -201,15 +201,15 @@ public void deleteEholdingsResourcesByResourceId(String resourceId, Map okapiHeaders, + Map headers, Handler> asyncResultHandler, Context vertxContext) { - userKbCredentialsService.findByUser(okapiHeaders) + userKbCredentialsService.findByUser(headers) .thenCompose(creds -> { ResourceTagsDataAttributes attributes = entity.getData().getAttributes(); resourceTagsPutBodyValidator.validate(entity, attributes); return updateResourceTags(createDbResource(resourceId, creds.getId(), attributes), - new OkapiData(okapiHeaders).getTenant()) + new RequestContext(headers).getTenant()) .thenAccept(ob -> asyncResultHandler.handle( Future.succeededFuture(PutEholdingsResourcesTagsByResourceIdResponse.respond200WithApplicationVndApiJson( convertToResourceTags(attributes))))); @@ -235,7 +235,7 @@ public void postEholdingsResourcesBulkFetch(String contentType, ResourcePostBulk private Function> processResourcePost( ResourcePostDataAttributes attributes) { - long titleId = parseTitleId(attributes.getTitleId()); + var titleId = parseTitleId(attributes.getTitleId()); PackageId packageId = parsePackageId(attributes.getPackageId()); return context -> (CompletableFuture) getObjectsForPostResource(titleId, packageId, context.getTitlesService(), context.getPackagesService()) @@ -244,11 +244,7 @@ private Function> processResourcePost postValidator.validateRelatedObjects(result.packageData(), title, result.titles()); ResourceSelectedPayload postRequest = new ResourceSelectedPayload(true, title.getTitleName(), title.getPubType(), attributes.getUrl()); - ResourceId resourceId = ResourceId.builder() - .providerIdPart(packageId.getProviderIdPart()) - .packageIdPart(packageId.getPackageIdPart()) - .titleIdPart(titleId) - .build(); + ResourceId resourceId = new ResourceId(packageId.providerIdPart(), packageId.packageIdPart(), titleId); return context.getResourcesService().postResource(postRequest, resourceId); }) .thenCompose(title -> CompletableFuture.completedFuture( @@ -262,7 +258,7 @@ private CompletableFuture fetchAccessType(ResourcePutRequest entity, return CompletableFuture.completedFuture(null); } else { return accessTypesService.findByCredentialsAndAccessTypeId(context.getCredentialsId(), accessTypeId, false, - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } } @@ -280,7 +276,7 @@ private CompletableFuture updateAccessType(String recordId, Titl private CompletableFuture updateRecordMapping(AccessType accessType, String recordId, RmApiTemplateContext context) { return accessTypeMappingsService.update(accessType, recordId, RecordType.RESOURCE, context.getCredentialsId(), - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } private CompletableFuture loadRelatedEntities(ResourceResult result, RmApiTemplateContext context) { @@ -308,7 +304,7 @@ private CompletableFuture deleteAssignedResources(String resourceId, RmApi } private CompletableFuture deleteTags(String resourceId, RmApiTemplateContext context) { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); UUID credentialsId = RowSetUtils.toUUID(context.getCredentialsId()); return resourceRepository.delete(resourceId, credentialsId, tenant) @@ -317,17 +313,17 @@ private CompletableFuture deleteTags(String resourceId, RmApiTemplateConte } private CompletionStage getObjectsForPostResource( - Long titleId, PackageId packageId, + int titleId, PackageId packageId, TitlesHoldingsIQService titlesService, PackagesHoldingsIQService packagesService) { CompletableFuture titleFuture = titlesService.retrieveTitle(titleId); - CompletableFuture<PackageByIdData> packageFuture = packagesService.retrievePackage(packageId); + CompletableFuture<PackageData> packageFuture = packagesService.retrievePackage(packageId.packageIdPart()); return CompletableFuture.allOf(titleFuture, packageFuture) .thenCompose(o -> { FilterQuery filterByName = FilterQuery.builder() .name(titleFuture.join().getTitleName()) .build(); - return titlesService.retrieveTitles(packageId.getProviderIdPart(), packageId.getPackageIdPart(), + return titlesService.retrieveTitles(packageId.providerIdPart(), packageId.packageIdPart(), filterByName, searchProperties.titlesSearchType(), Sort.RELEVANCE, 1, MAX_TITLE_COUNT); }) .thenCompose(titles -> CompletableFuture.completedFuture( @@ -372,7 +368,7 @@ private CompletableFuture<Title> processResourceUpdate(ResourcePutRequest entity private Function<ResourceNotFoundException, Response> error404ResourceNotFoundMapper() { return exception -> Response.status(SC_NOT_FOUND) - .header(CONTENT_TYPE, JSON_API_TYPE) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_TYPE) .entity(createError(RESOURCE_NOT_FOUND_MESSAGE)) .build(); } diff --git a/src/main/java/org/folio/rest/impl/EholdingsStatusImpl.java b/src/main/java/org/folio/rest/impl/EholdingsStatusImpl.java index daa74a10f..6dbfd51d5 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsStatusImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsStatusImpl.java @@ -20,7 +20,7 @@ import javax.ws.rs.core.Response; import org.apache.commons.lang3.mutable.MutableObject; import org.folio.holdingsiq.model.ConfigurationError; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.service.ConfigurationService; import org.folio.rest.aspect.HandleValidationErrors; import org.folio.rest.converter.configuration.StatusConverter; @@ -46,17 +46,17 @@ public EholdingsStatusImpl() { @Override @HandleValidationErrors - public void getEholdingsStatus(Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, + public void getEholdingsStatus(Map<String, String> headers, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { - headerValidator.validate(okapiHeaders); - MutableObject<OkapiData> okapiData = new MutableObject<>(); + headerValidator.validate(headers); + MutableObject<RequestContext> requestContext = new MutableObject<>(); CompletableFuture.completedFuture(null) .thenCompose(o -> { - okapiData.setValue(new OkapiData(okapiHeaders)); - return configurationService.retrieveConfiguration(okapiData.get()); + requestContext.setValue(new RequestContext(headers)); + return configurationService.retrieveConfiguration(requestContext.get()); }) .thenCompose(configuration -> configurationService.verifyCredentials(configuration, vertxContext, - okapiData.get()) + requestContext.get()) ) .thenAccept(verificationErrorsToResponse(asyncResultHandler)) .exceptionally(handleStatusException(asyncResultHandler)); diff --git a/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java index 53ce60458..e7e7a303f 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java @@ -39,7 +39,9 @@ import org.folio.rest.jaxrs.model.TitlePostRequest; import org.folio.rest.jaxrs.model.TitlePutRequest; import org.folio.rest.jaxrs.resource.EholdingsTitles; -import org.folio.rest.model.filter.Filter; +import org.folio.rest.model.filter.AccessTypeFilter; +import org.folio.rest.model.filter.TagFilter; +import org.folio.rest.model.filter.TitleFilter; import org.folio.rest.util.ErrorUtil; import org.folio.rest.util.IdParser; import org.folio.rest.util.template.RmApiTemplateContext; @@ -94,8 +96,7 @@ public void getEholdingsTitles(List<String> filterTags, List<String> filterAcces List<String> filterPackageIds, String include, String sort, int page, int count, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { - Filter filter = Filter.builder() - .recordType(RecordType.TITLE) + var filter = TitleFilter.builder() .filterTags(filterTags) .filterAccessType(filterAccessType) .filterSelected(filterSelected) @@ -139,7 +140,7 @@ public void postEholdingsTitles(String contentType, TitlePostRequest entity, Map @HandleValidationErrors public void getEholdingsTitlesByTitleId(String titleId, String include, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { - long titleIdLong = parseTitleId(titleId); + var titleIdLong = parseTitleId(titleId); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) .requestAction(context -> @@ -161,7 +162,7 @@ public void putEholdingsTitlesByTitleId(String titleId, String contentType, Titl Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { titleCommonRequestAttributesValidator.validate(entity.getData().getAttributes()); - Long parsedTitleId = parseTitleId(titleId); + var parsedTitleId = parseTitleId(titleId); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) .requestAction(context -> context.getTitlesService().retrieveTitle(parsedTitleId) @@ -182,15 +183,15 @@ public void putEholdingsTitlesByTitleId(String titleId, String contentType, Titl .executeWithResult(Title.class); } - private CompletableFuture<Titles> fetchTitlesByFilter(Filter filter, RmApiTemplateContext context) { + private CompletableFuture<Titles> fetchTitlesByFilter(TitleFilter filter, RmApiTemplateContext context) { if (filter.isTagsFilter()) { - return filteredEntitiesLoader.fetchTitlesByTagFilter(filter.createTagFilter(), context); + return filteredEntitiesLoader.fetchTitlesByTagFilter(TagFilter.from(filter), context); } else if (filter.isAccessTypeFilter()) { - return filteredEntitiesLoader.fetchTitlesByAccessTypeFilter(filter.createAccessTypeFilter(), context); + return filteredEntitiesLoader.fetchTitlesByAccessTypeFilter(AccessTypeFilter.from(filter), context); } else { return context.getTitlesService() .retrieveTitles(filter.createFilterQuery(), searchProperties.titlesSearchType(), - filter.getSort(), filter.getPage(), filter.getCount() + filter.resolveSort(), filter.getPage(), filter.getCount() ); } } @@ -223,7 +224,7 @@ private CompletableFuture<TitleResult> loadTags(TitleResult result, .stream() .map(IdParser::getResourceId) .toList(); - return tagRepository.findByRecordByIds(context.getOkapiData().getTenant(), resourceIds, RecordType.RESOURCE) + return tagRepository.findByRecordByIds(context.getRequestContext().getTenant(), resourceIds, RecordType.RESOURCE) .thenApply(tags -> { result.setResourceTagList(tags); return result; @@ -240,7 +241,7 @@ private CompletableFuture<TitleResult> updateTags(TitleResult result, RmApiTempl if (Objects.isNull(tags)) { return completedFuture(result); } else { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); UUID credentialsId = toUUID(context.getCredentialsId()); return updateStoredTitles(createDbTitle(result, credentialsId), tags, tenant) diff --git a/src/main/java/org/folio/rest/impl/LoadHoldingsImpl.java b/src/main/java/org/folio/rest/impl/LoadHoldingsImpl.java index 5e756b14e..d73885bd8 100644 --- a/src/main/java/org/folio/rest/impl/LoadHoldingsImpl.java +++ b/src/main/java/org/folio/rest/impl/LoadHoldingsImpl.java @@ -15,7 +15,7 @@ import javax.ws.rs.core.Response; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.repository.holdings.status.HoldingsStatusRepository; import org.folio.rest.annotations.Validate; import org.folio.rest.aspect.HandleValidationErrors; @@ -62,14 +62,14 @@ public LoadHoldingsImpl() { @Override @Validate @HandleValidationErrors - public void postEholdingsLoadingKbCredentials(String contentType, Map<String, String> okapiHeaders, + public void postEholdingsLoadingKbCredentials(String contentType, Map<String, String> headers, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { LOG.info("Received signal to start scheduled loading of holdings"); - validateAllCredentialsStatus(okapiHeaders) - .thenCompose(o -> credentialsService.findAll(okapiHeaders)) + validateAllCredentialsStatus(headers) + .thenCompose(o -> credentialsService.findAll(headers)) .thenApply(KbCredentialsCollection::getData) - .thenApply(credentialsList -> iterateOverCredentials(credentialsList, okapiHeaders)) + .thenApply(credentialsList -> iterateOverCredentials(credentialsList, headers)) .thenAccept(anyObj -> asyncResultHandler.handle( succeededFuture(PostEholdingsLoadingKbCredentialsResponse.respond204()))) .exceptionally(loadHoldingsErrorHandler.handle(asyncResultHandler)); @@ -78,11 +78,11 @@ public void postEholdingsLoadingKbCredentials(String contentType, Map<String, St @Override @Validate @HandleValidationErrors - public void postEholdingsLoadingKbCredentialsById(String id, String contentType, Map<String, String> okapiHeaders, + public void postEholdingsLoadingKbCredentialsById(String id, String contentType, Map<String, String> headers, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { LOG.info("Start loading of holdings for credentials: {}", id); - templateFactory.createTemplate(okapiHeaders, asyncResultHandler) + templateFactory.createTemplate(headers, asyncResultHandler) .withErrorHandler(loadHoldingsErrorHandler) .requestAction(this::validateAndStartLoading) .execute(); @@ -92,54 +92,54 @@ public void postEholdingsLoadingKbCredentialsById(String id, String contentType, @Validate @HandleValidationErrors public void getEholdingsLoadingKbCredentialsStatusById(String id, String contentType, - Map<String, String> okapiHeaders, + Map<String, String> headers, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { LOG.info("Getting holdings loading status"); - templateFactory.createTemplate(okapiHeaders, asyncResultHandler) + templateFactory.createTemplate(headers, asyncResultHandler) .withErrorHandler(loadHoldingsErrorHandler) .requestAction(context -> holdingsStatusRepository.findByCredentialsId(toUUID(context.getCredentialsId()), - context.getOkapiData().getTenant())) + context.getRequestContext().getTenant())) .executeWithResult(HoldingsLoadingStatus.class); } private CompletableFuture<Void> validateAndStartLoading(RmApiTemplateContext context) { - return holdingsService.canStartLoading(context.getCredentialsId(), context.getOkapiData().getTenant()) + return holdingsService.canStartLoading(context.getCredentialsId(), context.getRequestContext().getTenant()) .thenCompose(canStartLoading -> Boolean.TRUE.equals(canStartLoading) ? startLoading(context) : failedFuture(new ProcessInProgressException(LOADING_IN_PROGRESS_MESSAGE))); } - private CompletableFuture<Void> validateAllCredentialsStatus(Map<String, String> okapiHeaders) { - return holdingsService.canStartLoading(tenantId(okapiHeaders)) + private CompletableFuture<Void> validateAllCredentialsStatus(Map<String, String> headers) { + return holdingsService.canStartLoading(tenantId(headers)) .thenCompose(allCanStartLoading -> Boolean.TRUE.equals(allCanStartLoading) ? CompletableFuture.completedFuture(null) : failedFuture(new ProcessInProgressException(LOADING_IN_PROGRESS_MESSAGE))); } private CompletableFuture<Void> iterateOverCredentials(List<KbCredentials> credentialsList, - Map<String, String> okapiHeaders) { + Map<String, String> headers) { return CompletableFuture.allOf( credentialsList.stream() - .map(credentials -> buildContextAndRun(credentials, okapiHeaders)) + .map(credentials -> buildContextAndRun(credentials, headers)) .toArray(CompletableFuture[]::new) ); } - private CompletableFuture<Void> buildContextAndRun(KbCredentials credentials, Map<String, String> okapiHeaders) { - return startLoading(buildLoadingContext(credentials, okapiHeaders)); + private CompletableFuture<Void> buildContextAndRun(KbCredentials credentials, Map<String, String> headers) { + return startLoading(buildLoadingContext(credentials, headers)); } private CompletableFuture<Void> startLoading(RmApiTemplateContext context) { return holdingsStatusAuditService.clearExpiredRecords(context.getCredentialsId(), - context.getOkapiData().getTenant()) + context.getRequestContext().getTenant()) .thenCompose(o -> holdingsService.loadSingleHoldings(context)); } - private RmApiTemplateContext buildLoadingContext(KbCredentials credentials, Map<String, String> okapiHeaders) { + private RmApiTemplateContext buildLoadingContext(KbCredentials credentials, Map<String, String> headers) { return templateFactory.lookupContextBuilder() - .okapiData(new OkapiData(okapiHeaders)) + .requestContext(new RequestContext(headers)) .kbCredentials(credentials) .build(); } diff --git a/src/main/java/org/folio/rest/model/filter/AccessTypeFilter.java b/src/main/java/org/folio/rest/model/filter/AccessTypeFilter.java index 84db86e75..ffc58be05 100644 --- a/src/main/java/org/folio/rest/model/filter/AccessTypeFilter.java +++ b/src/main/java/org/folio/rest/model/filter/AccessTypeFilter.java @@ -14,4 +14,25 @@ public class AccessTypeFilter { private RecordType recordType; private int page; private int count; + + public static AccessTypeFilter from(Filter filter) { + AccessTypeFilter accessTypeFilter = new AccessTypeFilter(); + accessTypeFilter.setAccessTypeNames(filter.getFilterAccessType()); + accessTypeFilter.setCount(filter.getCount()); + accessTypeFilter.setPage(filter.getPage()); + + switch (filter) { + case PackageRecordFilter pf -> { + accessTypeFilter.setRecordIdPrefix(pf.getProviderId()); + accessTypeFilter.setRecordType(RecordType.PACKAGE); + } + case ResourceFilter rf -> { + accessTypeFilter.setRecordIdPrefix(rf.getPackageId()); + accessTypeFilter.setRecordType(RecordType.RESOURCE); + } + case TitleFilter tf -> accessTypeFilter.setRecordType(RecordType.RESOURCE); + case ProviderFilter prov -> { } + } + return accessTypeFilter; + } } diff --git a/src/main/java/org/folio/rest/model/filter/Filter.java b/src/main/java/org/folio/rest/model/filter/Filter.java index 42323773b..9a4770265 100644 --- a/src/main/java/org/folio/rest/model/filter/Filter.java +++ b/src/main/java/org/folio/rest/model/filter/Filter.java @@ -1,291 +1,60 @@ package org.folio.rest.model.filter; -import static java.util.Arrays.asList; -import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; -import static org.apache.commons.collections4.IterableUtils.countMatches; import static org.apache.commons.collections4.IterableUtils.matchesAll; -import static org.apache.commons.collections4.IterableUtils.matchesAny; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNumeric; import static org.folio.rest.util.RestConstants.FILTER_SELECTED_MAPPING; -import static org.folio.rest.util.RestConstants.SUPPORTED_PACKAGE_FILTER_TYPE_VALUES; -import static org.folio.rest.util.RestConstants.SUPPORTED_TITLE_FILTER_TYPE_VALUES; -import jakarta.validation.ValidationException; import java.util.List; -import java.util.Objects; -import lombok.Builder; -import lombok.Value; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Strings; -import org.folio.holdingsiq.model.FilterQuery; -import org.folio.holdingsiq.model.PackageId; +import org.folio.holdingsiq.model.Pageable; import org.folio.holdingsiq.model.Sort; import org.folio.repository.RecordType; -import org.folio.rest.util.IdParser; -@Value -@Builder -public class Filter { +public sealed interface Filter permits ProviderFilter, PackageRecordFilter, ResourceFilter, TitleFilter { - String query; - String filterIsxn; - String filterName; - String filterPublisher; - String filterSubject; - String filterType; - String filterCustom; - String filterSelected; - List<String> filterPackageIds; + String getSort(); - String packageId; - String providerId; + int getPage(); - List<String> filterTags; - List<String> filterAccessType; + int getCount(); - String sort; - int page; - int count; + List<String> getFilterTags(); - RecordType recordType; + List<String> getFilterAccessType(); - public static FilterBuilder builder() { - return new FilterBuilder() { + RecordType getRecordType(); - @Override - public Filter build() { - validate(); - return super.build(); - } - }; - } - - public static Filter getSortableFilter(Filter.FilterBuilder filterBuilder, String sort, int page, int count) { - return filterBuilder - .sort(sort) - .page(page) - .count(count) - .build(); - } - - public boolean isTagsFilter() { - return isCheckedFilter(filterTags, filterAccessType); - } + // Each impl returns its own search-criteria field values (used by isTagsFilter/isAccessTypeFilter) + List<String> searchCriteriaValues(); - public boolean isAccessTypeFilter() { - return isCheckedFilter(filterAccessType, filterTags); + // Default methods + default Sort resolveSort() { + return Sort.valueOf(getSort().toUpperCase()); } - public AccessTypeFilter createAccessTypeFilter() { - AccessTypeFilter accessTypeFilter = new AccessTypeFilter(); - accessTypeFilter.setAccessTypeNames(filterAccessType); - accessTypeFilter.setCount(count); - accessTypeFilter.setPage(page); - - if (recordType == RecordType.PACKAGE) { - accessTypeFilter.setRecordIdPrefix(providerId); - accessTypeFilter.setRecordType(RecordType.PACKAGE); - } else if (recordType == RecordType.RESOURCE) { - accessTypeFilter.setRecordIdPrefix(packageId); - accessTypeFilter.setRecordType(RecordType.RESOURCE); - } else if (recordType == RecordType.TITLE) { - accessTypeFilter.setRecordType(RecordType.RESOURCE); - } - return accessTypeFilter; - } - - public TagFilter createTagFilter() { - TagFilter.TagFilterBuilder builder = TagFilter.builder() - .tags(filterTags) - .recordType(recordType) - .offset((page - 1) * count) - .count(count); - - switch (recordType) { - case PACKAGE -> builder.recordIdPrefix(createRecordIdPrefix(providerId)); - case RESOURCE -> builder.recordIdPrefix(createRecordIdPrefix(packageId)); - case TITLE -> { - builder.recordType(RecordType.RESOURCE); - builder.recordIdPrefix(""); - } - case null, default -> builder.recordIdPrefix(""); - } - - return builder.build(); + default boolean isTagsFilter() { + return isFilteredBy(getFilterTags(), getFilterAccessType()); } - public FilterQuery createFilterQuery() { - return FilterQuery.builder() - .type(filterType) - .name(filterName) - .isxn(filterIsxn) - .subject(filterSubject) - .publisher(filterPublisher) - .selected(getFilterSelected()) - .packageIds(getFilterPackageIds()) - .build(); + default boolean isAccessTypeFilter() { + return isFilteredBy(getFilterAccessType(), getFilterTags()); } - public Long getProviderId() { - return IdParser.parseProviderId(providerId); + default Pageable toPageable() { + return new Pageable(getPage(), getCount(), resolveSort()); } - public PackageId getPackageId() { - return IdParser.parsePackageId(packageId); + // Private helper + private boolean isFilteredBy(List<String> primary, List<String> other) { + return isNotEmpty(primary) + && matchesAll(primary, StringUtils::isNotBlank) + && CollectionUtils.isEmpty(other) + && matchesAll(searchCriteriaValues(), StringUtils::isBlank); } - public String getFilterSelected() { - return filterSelected == null ? null : FILTER_SELECTED_MAPPING.get(filterSelected); - } - - public List<Integer> getFilterPackageIds() { - return filterPackageIds == null ? null : filterPackageIds.stream() - .map(Integer::parseInt) - .toList(); - } - - public Boolean getFilterCustom() { - return filterCustom == null ? null : Boolean.parseBoolean(filterCustom); - } - - public Sort getSort() { - return Sort.valueOf(sort.toUpperCase()); - } - - private String createRecordIdPrefix(String providerId) { - return isBlank(providerId) ? "" : Strings.CS.appendIfMissing(providerId, "-"); - } - - private boolean isCheckedFilter(List<String> checkedFilter, List<String> otherFilter) { - return isNotEmpty(checkedFilter) - && matchesAll(checkedFilter, StringUtils::isNotBlank) - && CollectionUtils.isEmpty(otherFilter) - && matchesAll( - asList(query, filterIsxn, filterName, filterPublisher, filterSubject, filterCustom, filterSelected), - StringUtils::isBlank); - } - - public static class FilterBuilder { - - private static final String INVALID_QUERY_PARAMETER_MESSAGE = "Search parameter cannot be empty"; - private static final String INVALID_SORT_PARAMETER_MESSAGE = "Invalid Query Parameter for sort"; - private static final String INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE = - "Invalid Query Parameter for filter[custom]: only 'true' is supported"; - private static final String INVALID_FILTER_TYPE_PARAMETER_MESSAGE = "Invalid Query Parameter for filter[type]"; - private static final String INVALID_FILTER_SELECTED_PARAMETER_MESSAGE = - "Invalid Query Parameter for filter[selected]"; - private static final String INVALID_FILTER_PACKAGE_IDS_PARAMETER_MESSAGE = - "Invalid Query Parameter for filter[packageIds]"; - private static final String CONFLICTING_KEYWORD_SEARCH_PARAMETERS_MESSAGE = "Conflicting filter parameters"; - private static final String MISSING_KEYWORD_SEARCH_PARAMETERS_MESSAGE = - "All of filter[name], filter[isxn], filter[subject] and filter[publisher] cannot be missing."; - private static final String INVALID_KEYWORD_SEARCH_PARAMETERS_MESSAGE = - "Value of required parameter filter[name], filter[isxn], filter[subject] or filter[publisher] is missing."; - - void validate() { - if (isEmpty(this.filterTags) && isEmpty(this.filterAccessType)) { - validateSort(); - - if (this.recordType == RecordType.PROVIDER) { - validateQuery(); - } else if (this.recordType == RecordType.PACKAGE) { - validateQuery(); - validatePackageFilterType(); - validateFilterCustom(); - validateFilterSelected(); - validateProviderId(); - } else if (this.recordType == RecordType.RESOURCE) { - validatePackageId(); - validateTitleFilterType(); - validateFilterSelected(); - validateKeywordSearch(true); - } else if (this.recordType == RecordType.TITLE) { - validateTitleFilterType(); - validateFilterSelected(); - validateFilterPackageIds(); - validateKeywordSearch(false); - } - } - } - - private void validateKeywordSearch(boolean allowNullFilters) { - List<String> searchParameters = - asList(this.filterName, this.filterIsxn, this.filterSubject, this.filterPublisher); - - long nonNullFilters = countMatches(searchParameters, Objects::nonNull); - - if (nonNullFilters > 1) { - throw new ValidationException(CONFLICTING_KEYWORD_SEARCH_PARAMETERS_MESSAGE); - } - if (nonNullFilters < 1 && !allowNullFilters) { - throw new ValidationException(MISSING_KEYWORD_SEARCH_PARAMETERS_MESSAGE); - } - if (matchesAny(searchParameters, StringUtils.EMPTY::equals)) { - throw new ValidationException(INVALID_KEYWORD_SEARCH_PARAMETERS_MESSAGE); - } - } - - private void validateFilterSelected() { - if (this.filterSelected != null && !FILTER_SELECTED_MAPPING.containsKey(this.filterSelected)) { - throw new ValidationException(INVALID_FILTER_SELECTED_PARAMETER_MESSAGE); - } - } - - private void validateFilterPackageIds() { - if (this.filterPackageIds != null && !this.filterPackageIds.isEmpty()) { - this.filterPackageIds.forEach(filterPackageId -> { - if (!isNumeric(filterPackageId)) { - throw new ValidationException(INVALID_FILTER_PACKAGE_IDS_PARAMETER_MESSAGE); - } - }); - } - } - - private void validatePackageFilterType() { - if (this.filterType != null - && !SUPPORTED_PACKAGE_FILTER_TYPE_VALUES.contains(this.filterType)) { - throw new ValidationException(INVALID_FILTER_TYPE_PARAMETER_MESSAGE); - } - } - - private void validateTitleFilterType() { - if (this.filterType != null - && !SUPPORTED_TITLE_FILTER_TYPE_VALUES.contains(this.filterType)) { - throw new ValidationException(INVALID_FILTER_TYPE_PARAMETER_MESSAGE); - } - } - - private void validateFilterCustom() { - if (this.filterCustom != null && !Boolean.parseBoolean(this.filterCustom)) { - throw new ValidationException(INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE); - } - } - - private void validateSort() { - if (!Sort.contains(this.sort.toUpperCase())) { - throw new ValidationException(INVALID_SORT_PARAMETER_MESSAGE); - } - } - - private void validateQuery() { - if ("".equals(this.query)) { - throw new ValidationException(INVALID_QUERY_PARAMETER_MESSAGE); - } - } - - private void validateProviderId() { - if (this.providerId != null) { - IdParser.parseProviderId(this.providerId); - } - } - - private void validatePackageId() { - if (this.packageId != null) { - IdParser.parsePackageId(this.packageId); - } - } + // Shared utility for resolveFilterSelected (used by 3 implementations) + static String mapFilterSelected(String filterSelected) { + return filterSelected == null ? null : FILTER_SELECTED_MAPPING.get(filterSelected).getValue(); } } diff --git a/src/main/java/org/folio/rest/model/filter/FilterValidator.java b/src/main/java/org/folio/rest/model/filter/FilterValidator.java new file mode 100644 index 000000000..45dd20de4 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/FilterValidator.java @@ -0,0 +1,32 @@ +package org.folio.rest.model.filter; + +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; + +public sealed interface FilterValidator<F extends Filter> permits PackageFilterValidator { + + void validate(@NonNull F filter); + + default Optional<String> validate(@NonNull F filter, + @NonNull Function<F, String> paramExtractor, + @NonNull Predicate<String> validator, + @NonNull String errorMessage) { + var param = paramExtractor.apply(filter); + if (validator.test(param)) { + return Optional.empty(); + } else { + return Optional.of(errorMessage); + } + } + + default Optional<String> validate(@NonNull F filter, @NonNull FilterValidatorLogic<F> logic) { + var param = logic.extractor().apply(filter); + if (logic.validator().test(param)) { + return Optional.empty(); + } else { + return Optional.of(logic.errorMessage()); + } + } +} diff --git a/src/main/java/org/folio/rest/model/filter/FilterValidatorLogic.java b/src/main/java/org/folio/rest/model/filter/FilterValidatorLogic.java new file mode 100644 index 000000000..40b1d7f14 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/FilterValidatorLogic.java @@ -0,0 +1,18 @@ +package org.folio.rest.model.filter; + +import java.util.function.Function; +import java.util.function.Predicate; +import org.jspecify.annotations.NonNull; + +public record FilterValidatorLogic<F extends Filter>( + Function<F, String> extractor, + Predicate<String> validator, + String errorMessage +) { + + public static <F extends Filter> FilterValidatorLogic<F> of(@NonNull Function<F, String> extractor, + @NonNull Predicate<String> validator, + @NonNull String errorMessage) { + return new FilterValidatorLogic<>(extractor, validator, errorMessage); + } +} diff --git a/src/main/java/org/folio/rest/model/filter/FilterValidators.java b/src/main/java/org/folio/rest/model/filter/FilterValidators.java new file mode 100644 index 000000000..86f920126 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/FilterValidators.java @@ -0,0 +1,175 @@ +package org.folio.rest.model.filter; + +import static java.util.Arrays.asList; +import static org.apache.commons.collections4.IterableUtils.countMatches; +import static org.apache.commons.collections4.IterableUtils.matchesAny; +import static org.apache.commons.lang3.StringUtils.isNumeric; +import static org.folio.rest.util.RestConstants.FILTER_SELECTED_MAPPING; +import static org.folio.rest.util.RestConstants.SUPPORTED_PACKAGE_FILTER_TYPE_VALUES; +import static org.folio.rest.util.RestConstants.SUPPORTED_TITLE_FILTER_TYPE_VALUES; + +import jakarta.validation.ValidationException; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.folio.holdingsiq.model.PackageSearchField; +import org.folio.holdingsiq.model.SearchType; +import org.folio.holdingsiq.model.Sort; +import org.folio.rest.util.IdParser; + +public final class FilterValidators { + + static final String INVALID_QUERY_PARAMETER_MESSAGE = "Search parameter cannot be empty"; + static final String INVALID_SORT_PARAMETER_MESSAGE = "Invalid Query Parameter for sort"; + static final String INVALID_QUERY_TYPE_PARAMETER_MESSAGE = "Invalid Query Parameter for qType"; + static final String INVALID_QUERY_FIELD_PARAMETER_MESSAGE = "Invalid Query Parameter for qField"; + static final String INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE = + "Invalid Query Parameter for filter[custom]: only 'true' is supported"; + static final String INVALID_FILTER_TYPE_PARAMETER_MESSAGE = "Invalid Query Parameter for filter[type]"; + static final String INVALID_FILTER_SELECTED_PARAMETER_MESSAGE = + "Invalid Query Parameter for filter[selected]"; + static final String INVALID_FILTER_PACKAGE_IDS_PARAMETER_MESSAGE = + "Invalid Query Parameter for filter[packageIds]"; + static final String CONFLICTING_KEYWORD_SEARCH_PARAMETERS_MESSAGE = "Conflicting filter parameters"; + static final String MISSING_KEYWORD_SEARCH_PARAMETERS_MESSAGE = + "All of filter[name], filter[isxn], filter[subject] and filter[publisher] cannot be missing."; + static final String INVALID_KEYWORD_SEARCH_PARAMETERS_MESSAGE = + "Value of required parameter filter[name], filter[isxn], filter[subject] or filter[publisher] is missing."; + + private FilterValidators() { + } + + public static void validateProvider(ProviderFilter filter) { + if (CollectionUtils.isNotEmpty(filter.getFilterTags()) + || CollectionUtils.isNotEmpty(filter.getFilterAccessType())) { + return; + } + validateSort(filter.getSort()); + validateQuery(filter.getQuery()); + } + + public static void validatePackage(PackageRecordFilter filter) { + if (CollectionUtils.isNotEmpty(filter.getFilterTags()) + || CollectionUtils.isNotEmpty(filter.getFilterAccessType())) { + return; + } + validateSort(filter.getSort()); + validateQuery(filter.getQuery()); + validateQueryType(filter.getQueryType()); + validateQueryField(filter.getQueryField()); + validateFilterType(filter.getFilterType(), SUPPORTED_PACKAGE_FILTER_TYPE_VALUES); + validateFilterCustom(filter.getFilterCustom()); + validateFilterSelected(filter.getFilterSelected()); + validateProviderId(filter.getProviderId()); + } + + public static void validateResource(ResourceFilter filter) { + if (CollectionUtils.isNotEmpty(filter.getFilterTags()) + || CollectionUtils.isNotEmpty(filter.getFilterAccessType())) { + return; + } + validateSort(filter.getSort()); + validatePackageId(filter.getPackageId()); + validateFilterType(filter.getFilterType(), SUPPORTED_TITLE_FILTER_TYPE_VALUES); + validateFilterSelected(filter.getFilterSelected()); + validateKeywordSearch(filter.getFilterName(), filter.getFilterIsxn(), + filter.getFilterSubject(), filter.getFilterPublisher(), true); + } + + public static void validateTitle(TitleFilter filter) { + if (CollectionUtils.isNotEmpty(filter.getFilterTags()) + || CollectionUtils.isNotEmpty(filter.getFilterAccessType())) { + return; + } + validateSort(filter.getSort()); + validateFilterType(filter.getFilterType(), SUPPORTED_TITLE_FILTER_TYPE_VALUES); + validateFilterSelected(filter.getFilterSelected()); + validateFilterPackageIds(filter.getFilterPackageIds()); + validateKeywordSearch(filter.getFilterName(), filter.getFilterIsxn(), + filter.getFilterSubject(), filter.getFilterPublisher(), false); + } + + private static void validateSort(String sort) { + if (!Sort.contains(sort.toUpperCase())) { + throw new ValidationException(INVALID_SORT_PARAMETER_MESSAGE); + } + } + + private static void validateQuery(String query) { + if ("".equals(query)) { + throw new ValidationException(INVALID_QUERY_PARAMETER_MESSAGE); + } + } + + private static void validateQueryType(String queryType) { + if (!SearchType.contains(queryType.toUpperCase())) { + throw new ValidationException(INVALID_QUERY_TYPE_PARAMETER_MESSAGE); + } + } + + private static void validateQueryField(String queryField) { + if (!PackageSearchField.contains(queryField.toUpperCase())) { + throw new ValidationException(INVALID_QUERY_FIELD_PARAMETER_MESSAGE); + } + } + + private static void validateFilterType(String filterType, Collection<String> supportedValues) { + if (filterType != null && !supportedValues.contains(filterType)) { + throw new ValidationException(INVALID_FILTER_TYPE_PARAMETER_MESSAGE); + } + } + + private static void validateFilterCustom(String filterCustom) { + if (filterCustom != null && !Boolean.parseBoolean(filterCustom)) { + throw new ValidationException(INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE); + } + } + + private static void validateFilterSelected(String filterSelected) { + if (filterSelected != null && !FILTER_SELECTED_MAPPING.containsKey(filterSelected)) { + throw new ValidationException(INVALID_FILTER_SELECTED_PARAMETER_MESSAGE); + } + } + + private static void validateFilterPackageIds(List<String> packageIds) { + if (packageIds != null && !packageIds.isEmpty()) { + packageIds.forEach(id -> { + if (!isNumeric(id)) { + throw new ValidationException(INVALID_FILTER_PACKAGE_IDS_PARAMETER_MESSAGE); + } + }); + } + } + + private static void validateKeywordSearch(String filterName, String filterIsxn, + String filterSubject, String filterPublisher, + boolean allowNullFilters) { + List<String> searchParameters = asList(filterName, filterIsxn, filterSubject, filterPublisher); + + long nonNullFilters = countMatches(searchParameters, Objects::nonNull); + + if (nonNullFilters > 1) { + throw new ValidationException(CONFLICTING_KEYWORD_SEARCH_PARAMETERS_MESSAGE); + } + if (nonNullFilters < 1 && !allowNullFilters) { + throw new ValidationException(MISSING_KEYWORD_SEARCH_PARAMETERS_MESSAGE); + } + if (matchesAny(searchParameters, StringUtils.EMPTY::equals)) { + throw new ValidationException(INVALID_KEYWORD_SEARCH_PARAMETERS_MESSAGE); + } + } + + private static void validateProviderId(String providerId) { + if (providerId != null) { + IdParser.parseProviderId(providerId); + } + } + + private static void validatePackageId(String packageId) { + if (packageId != null) { + IdParser.parsePackageId(packageId); + } + } +} diff --git a/src/main/java/org/folio/rest/model/filter/PackageFilterParams.java b/src/main/java/org/folio/rest/model/filter/PackageFilterParams.java new file mode 100644 index 000000000..03eb014ac --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/PackageFilterParams.java @@ -0,0 +1,13 @@ +package org.folio.rest.model.filter; + +import java.util.List; + +public record PackageFilterParams( + String filterCustom, + String filterSelected, + String filterType, + String filterVisibility, + String filterFreeAccess, + List<String> filterTags, + List<String> filterAccessType +) { } diff --git a/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java b/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java new file mode 100644 index 000000000..d173b981d --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java @@ -0,0 +1,123 @@ +package org.folio.rest.model.filter; + +import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; +import static org.folio.rest.model.filter.FilterValidatorLogic.of; +import static org.folio.rest.util.RestConstants.FILTER_FREE_ACCESS_MAPPING; +import static org.folio.rest.util.RestConstants.FILTER_SELECTED_MAPPING; +import static org.folio.rest.util.RestConstants.FILTER_VISIBILITY_MAPPING; +import static org.folio.rest.util.RestConstants.SUPPORTED_PACKAGE_FILTER_TYPE_VALUES; + +import java.util.List; +import java.util.Optional; +import org.folio.holdingsiq.model.PackageSearchField; +import org.folio.holdingsiq.model.SearchType; +import org.folio.holdingsiq.model.Sort; +import org.folio.rest.exception.QueryParamsValidationException; +import org.jspecify.annotations.NonNull; + +public final class PackageFilterValidator implements FilterValidator<PackageRecordFilter> { + + static final String INVALID_QUERY_PARAMETER_MESSAGE = "Invalid Query Parameter for q: cannot be empty"; + static final String INVALID_SORT_PARAMETER_MESSAGE = "Invalid Query Parameter for sort"; + static final String INVALID_QUERY_TYPE_PARAMETER_MESSAGE = "Invalid Query Parameter for qType"; + static final String INVALID_QUERY_FIELD_PARAMETER_MESSAGE = "Invalid Query Parameter for qField"; + static final String INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE = + "Invalid Query Parameter for filter[custom]: only 'true' is supported"; + static final String INVALID_FILTER_TYPE_PARAMETER_MESSAGE = "Invalid Query Parameter for filter[type]"; + static final String INVALID_FILTER_FREE_ACCESS_PARAMETER_MESSAGE = "Invalid Query Parameter for filter[free-access]"; + static final String INVALID_FILTER_VISIBILITY_PARAMETER_MESSAGE = "Invalid Query Parameter for filter[visibility]"; + static final String INVALID_FILTER_SELECTED_PARAMETER_MESSAGE = + "Invalid Query Parameter for filter[selected]"; + + private static final List<FilterValidatorLogic<PackageRecordFilter>> VALIDATORS = List.of( + of(PackageRecordFilter::getSort, PackageFilterValidator::isSortValid, INVALID_SORT_PARAMETER_MESSAGE), + of(PackageRecordFilter::getQueryType, PackageFilterValidator::isQueryTypeValid, + INVALID_QUERY_TYPE_PARAMETER_MESSAGE), + of(PackageRecordFilter::getQueryField, PackageFilterValidator::isQueryFieldValid, + INVALID_QUERY_FIELD_PARAMETER_MESSAGE), + of(PackageRecordFilter::getQuery, PackageFilterValidator::isQueryValid, INVALID_QUERY_PARAMETER_MESSAGE), + of(PackageRecordFilter::getFilterType, PackageFilterValidator::isFilterTypeValid, + INVALID_FILTER_TYPE_PARAMETER_MESSAGE), + of(PackageRecordFilter::getFilterCustom, PackageFilterValidator::isFilterCustomValid, + INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE), + of(PackageRecordFilter::getFilterSelected, PackageFilterValidator::isFilterSelectedValid, + INVALID_FILTER_SELECTED_PARAMETER_MESSAGE), + of(PackageRecordFilter::getFilterVisibility, PackageFilterValidator::isFilterVisibilityValid, + INVALID_FILTER_VISIBILITY_PARAMETER_MESSAGE), + of(PackageRecordFilter::getFilterFreeAccess, PackageFilterValidator::isFilterFreeAccessValid, + INVALID_FILTER_FREE_ACCESS_PARAMETER_MESSAGE) + ); + + @Override + public void validate(@NonNull PackageRecordFilter filter) { + if (isNotEmpty(filter.getFilterTags()) + || isNotEmpty(filter.getFilterAccessType())) { + return; + } + var failMessages = VALIDATORS.stream() + .map(logic -> validate(filter, logic)) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + if (!failMessages.isEmpty()) { + throw new QueryParamsValidationException(failMessages); + } + } + + private static boolean isFilterFreeAccessValid(String filterFreeAccess) { + if (filterFreeAccess == null) { + return true; + } + return FILTER_FREE_ACCESS_MAPPING.containsKey(filterFreeAccess); + } + + private static boolean isFilterVisibilityValid(String filterVisibility) { + if (filterVisibility == null) { + return true; + } + return FILTER_VISIBILITY_MAPPING.containsKey(filterVisibility); + } + + private static boolean isFilterSelectedValid(String filterSelected) { + if (filterSelected == null) { + return true; + } + return FILTER_SELECTED_MAPPING.containsKey(filterSelected); + } + + private static boolean isFilterCustomValid(String filterCustom) { + if (filterCustom == null) { + return true; + } + return Boolean.parseBoolean(filterCustom); + } + + private static boolean isFilterTypeValid(String filterType) { + if (filterType == null) { + return true; + } + return SUPPORTED_PACKAGE_FILTER_TYPE_VALUES.contains(filterType); + } + + private static boolean isQueryValid(String anObject) { + return !"".equals(anObject); + } + + private static boolean isQueryFieldValid(String queryField) { + if (queryField == null) { + return true; + } + return PackageSearchField.contains(queryField); + } + + private static boolean isQueryTypeValid(String queryType) { + if (queryType == null) { + return true; + } + return SearchType.contains(queryType); + } + + private static boolean isSortValid(String sort) { + return Sort.contains(sort.toUpperCase()); + } +} diff --git a/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java b/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java new file mode 100644 index 000000000..111d56e72 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java @@ -0,0 +1,109 @@ +package org.folio.rest.model.filter; + +import static java.util.Arrays.asList; + +import java.util.List; +import java.util.Optional; +import lombok.Builder; +import lombok.Value; +import org.folio.holdingsiq.model.PackageFilter; +import org.folio.holdingsiq.model.PackageFilterFreeAccess; +import org.folio.holdingsiq.model.PackageFilterSelected; +import org.folio.holdingsiq.model.PackageFilterType; +import org.folio.holdingsiq.model.PackageFilterVisibility; +import org.folio.holdingsiq.model.PackageSearchField; +import org.folio.holdingsiq.model.SearchType; +import org.folio.properties.common.SearchProperties; +import org.folio.repository.RecordType; +import org.folio.rest.util.IdParser; +import org.folio.rest.util.RestConstants; + +@Value +@Builder +public class PackageRecordFilter implements Filter { + + private static final FilterValidator<PackageRecordFilter> VALIDATOR = new PackageFilterValidator(); + + String query; + String queryField; + String queryType; + boolean highlight; + + String providerId; + String filterCustom; + String filterSelected; + String filterType; + String filterVisibility; + String filterFreeAccess; + String sort; + int page; + int count; + List<String> filterTags; + List<String> filterAccessType; + + public static PackageRecordFilterBuilder builder() { + return new PackageRecordFilterBuilder() { + @Override + public PackageRecordFilter build() { + PackageRecordFilter filter = super.build(); + VALIDATOR.validate(filter); + return filter; + } + }; + } + + public Optional<SearchType> getSearchType() { + return Optional.ofNullable(queryType).map(SearchType::fromValue); + } + + public Optional<PackageSearchField> getPackageSearchField() { + return Optional.ofNullable(queryField).map(PackageSearchField::fromValue); + } + + public Optional<PackageFilterSelected> getPackageFilterSelected() { + return Optional.ofNullable(filterSelected).map(RestConstants.FILTER_SELECTED_MAPPING::get); + } + + public Optional<PackageFilterType> getPackageFilterType() { + return Optional.ofNullable(filterType).map(PackageFilterType::fromValue); + } + + public Optional<PackageFilterFreeAccess> getPackageFilterFreeAccess() { + return Optional.ofNullable(filterFreeAccess).map(RestConstants.FILTER_FREE_ACCESS_MAPPING::get); + } + + public Optional<PackageFilterVisibility> getPackageFilterVisibility() { + return Optional.ofNullable(filterVisibility).map(RestConstants.FILTER_VISIBILITY_MAPPING::get); + } + + @Override + public RecordType getRecordType() { + return RecordType.PACKAGE; + } + + @Override + public List<String> searchCriteriaValues() { + return asList(query, filterCustom, filterSelected); + } + + public Integer parseProviderId() { + return IdParser.parseProviderId(providerId); + } + + public Boolean resolveFilterCustom() { + return filterCustom == null ? null : Boolean.parseBoolean(filterCustom); + } + + public PackageFilter toClientFilter(SearchProperties searchProperties) { + return PackageFilter.builder() + .query(query) + .searchType(getSearchType().orElse(SearchType.fromValue(searchProperties.packagesSearchType()))) + .searchField(getPackageSearchField().orElse(null)) + .highlightTag(highlight ? searchProperties.highlightTag() : null) + .filterSelected(getPackageFilterSelected().orElse(null)) + .filterType(getPackageFilterType().orElse(null)) + .filterPackageFreeAccess(getPackageFilterFreeAccess().orElse(null)) + .filterVisibility(getPackageFilterVisibility().orElse(null)) + .build(); + } +} diff --git a/src/main/java/org/folio/rest/model/filter/ProviderFilter.java b/src/main/java/org/folio/rest/model/filter/ProviderFilter.java new file mode 100644 index 000000000..8d172ddca --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/ProviderFilter.java @@ -0,0 +1,41 @@ +package org.folio.rest.model.filter; + +import static java.util.Arrays.asList; + +import java.util.List; +import lombok.Builder; +import lombok.Value; +import org.folio.repository.RecordType; + +@Value +@Builder +public class ProviderFilter implements Filter { + + String query; + String sort; + int page; + int count; + List<String> filterTags; + List<String> filterAccessType; + + @Override + public RecordType getRecordType() { + return RecordType.PROVIDER; + } + + @Override + public List<String> searchCriteriaValues() { + return asList(query); + } + + public static ProviderFilterBuilder builder() { + return new ProviderFilterBuilder() { + @Override + public ProviderFilter build() { + ProviderFilter filter = super.build(); + FilterValidators.validateProvider(filter); + return filter; + } + }; + } +} diff --git a/src/main/java/org/folio/rest/model/filter/ResourceFilter.java b/src/main/java/org/folio/rest/model/filter/ResourceFilter.java new file mode 100644 index 000000000..086eda3bc --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/ResourceFilter.java @@ -0,0 +1,69 @@ +package org.folio.rest.model.filter; + +import static java.util.Arrays.asList; + +import java.util.List; +import lombok.Builder; +import lombok.Value; +import org.folio.holdingsiq.model.FilterQuery; +import org.folio.holdingsiq.model.PackageId; +import org.folio.repository.RecordType; +import org.folio.rest.util.IdParser; + +@Value +@Builder +public class ResourceFilter implements Filter { + + String packageId; + String filterSelected; + String filterType; + String filterName; + String filterIsxn; + String filterSubject; + String filterPublisher; + String sort; + int page; + int count; + List<String> filterTags; + List<String> filterAccessType; + + @Override + public RecordType getRecordType() { + return RecordType.RESOURCE; + } + + @Override + public List<String> searchCriteriaValues() { + return asList(filterIsxn, filterName, filterPublisher, filterSubject, filterSelected); + } + + public PackageId parsePackageId() { + return IdParser.parsePackageId(packageId); + } + + public String resolveFilterSelected() { + return Filter.mapFilterSelected(filterSelected); + } + + public FilterQuery createFilterQuery() { + return FilterQuery.builder() + .type(filterType) + .name(filterName) + .isxn(filterIsxn) + .subject(filterSubject) + .publisher(filterPublisher) + .selected(resolveFilterSelected()) + .build(); + } + + public static ResourceFilterBuilder builder() { + return new ResourceFilterBuilder() { + @Override + public ResourceFilter build() { + ResourceFilter filter = super.build(); + FilterValidators.validateResource(filter); + return filter; + } + }; + } +} diff --git a/src/main/java/org/folio/rest/model/filter/TagFilter.java b/src/main/java/org/folio/rest/model/filter/TagFilter.java index f3a26191e..dbc176c02 100644 --- a/src/main/java/org/folio/rest/model/filter/TagFilter.java +++ b/src/main/java/org/folio/rest/model/filter/TagFilter.java @@ -1,8 +1,11 @@ package org.folio.rest.model.filter; +import static org.apache.commons.lang3.StringUtils.isBlank; + import java.util.List; import lombok.Builder; import lombok.Value; +import org.apache.commons.lang3.Strings; import org.folio.repository.RecordType; @Value @@ -14,4 +17,28 @@ public class TagFilter { RecordType recordType; int offset; int count; + + public static TagFilter from(Filter filter) { + TagFilterBuilder builder = TagFilter.builder() + .tags(filter.getFilterTags()) + .recordType(filter.getRecordType()) + .offset((filter.getPage() - 1) * filter.getCount()) + .count(filter.getCount()); + + switch (filter) { + case PackageRecordFilter pf -> builder.recordIdPrefix(ensureTrailingDash(pf.getProviderId())); + case ResourceFilter rf -> builder.recordIdPrefix(ensureTrailingDash(rf.getPackageId())); + case TitleFilter tf -> { + builder.recordType(RecordType.RESOURCE); + builder.recordIdPrefix(""); + } + case ProviderFilter prov -> builder.recordIdPrefix(""); + } + + return builder.build(); + } + + private static String ensureTrailingDash(String id) { + return isBlank(id) ? "" : Strings.CS.appendIfMissing(id, "-"); + } } diff --git a/src/main/java/org/folio/rest/model/filter/TitleFilter.java b/src/main/java/org/folio/rest/model/filter/TitleFilter.java new file mode 100644 index 000000000..70c3c2592 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/TitleFilter.java @@ -0,0 +1,70 @@ +package org.folio.rest.model.filter; + +import static java.util.Arrays.asList; + +import java.util.List; +import lombok.Builder; +import lombok.Value; +import org.folio.holdingsiq.model.FilterQuery; +import org.folio.repository.RecordType; + +@Value +@Builder +public class TitleFilter implements Filter { + + String filterSelected; + String filterType; + String filterName; + String filterIsxn; + String filterSubject; + String filterPublisher; + List<String> filterPackageIds; + String sort; + int page; + int count; + List<String> filterTags; + List<String> filterAccessType; + + @Override + public RecordType getRecordType() { + return RecordType.TITLE; + } + + @Override + public List<String> searchCriteriaValues() { + return asList(filterIsxn, filterName, filterPublisher, filterSubject, filterSelected); + } + + public String resolveFilterSelected() { + return Filter.mapFilterSelected(filterSelected); + } + + public List<Integer> resolveFilterPackageIds() { + return filterPackageIds == null ? null : filterPackageIds.stream() + .map(Integer::parseInt) + .toList(); + } + + public FilterQuery createFilterQuery() { + return FilterQuery.builder() + .type(filterType) + .name(filterName) + .isxn(filterIsxn) + .subject(filterSubject) + .publisher(filterPublisher) + .selected(resolveFilterSelected()) + .packageIds(resolveFilterPackageIds()) + .build(); + } + + public static TitleFilterBuilder builder() { + return new TitleFilterBuilder() { + @Override + public TitleFilter build() { + TitleFilter filter = super.build(); + FilterValidators.validateTitle(filter); + return filter; + } + }; + } +} diff --git a/src/main/java/org/folio/rest/model/query/PackageSearchParams.java b/src/main/java/org/folio/rest/model/query/PackageSearchParams.java new file mode 100644 index 000000000..5275795b0 --- /dev/null +++ b/src/main/java/org/folio/rest/model/query/PackageSearchParams.java @@ -0,0 +1,8 @@ +package org.folio.rest.model.query; + +public record PackageSearchParams( + String query, + String queryField, + String queryType, + boolean highlight +) { } diff --git a/src/main/java/org/folio/rest/util/ErrorUtil.java b/src/main/java/org/folio/rest/util/ErrorUtil.java index cbbd2bcdc..ea5fa83f2 100644 --- a/src/main/java/org/folio/rest/util/ErrorUtil.java +++ b/src/main/java/org/folio/rest/util/ErrorUtil.java @@ -19,6 +19,15 @@ public final class ErrorUtil { private ErrorUtil() { } + public static JsonapiError createErrors(List<String> errorMessage) { + var jsonapiErrorResponses = errorMessage.stream() + .map(msg -> createErrorResponse(msg, null)) + .toList(); + return new JsonapiError() + .withErrors(jsonapiErrorResponses) + .withJsonapi(RestConstants.JSONAPI); + } + public static JsonapiError createError(String errorMessage) { return createError(errorMessage, null); } diff --git a/src/main/java/org/folio/rest/util/ExceptionMappers.java b/src/main/java/org/folio/rest/util/ExceptionMappers.java index 23b92f211..200bb0659 100644 --- a/src/main/java/org/folio/rest/util/ExceptionMappers.java +++ b/src/main/java/org/folio/rest/util/ExceptionMappers.java @@ -1,14 +1,14 @@ package org.folio.rest.util; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_CONFLICT; -import static org.apache.http.HttpStatus.SC_FORBIDDEN; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; import static org.apache.http.protocol.HTTP.CONTENT_TYPE; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_CONFLICT; +import static org.folio.HttpStatus.SC_FORBIDDEN; +import static org.folio.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; import static org.folio.rest.util.ErrorUtil.createError; import static org.folio.rest.util.ErrorUtil.createErrorFromRmApiResponse; import static org.folio.rest.util.RestConstants.JSON_API_TYPE; @@ -281,7 +281,7 @@ public static Function<ProcessInProgressException, Response> error409ProcessInPr */ public static Function<InputValidationException, Response> error422InputValidationMapper() { return exception -> - Response.status(SC_UNPROCESSABLE_ENTITY) + Response.status(SC_UNPROCESSABLE_CONTENT) .header(CONTENT_TYPE, JSON_API_TYPE) .entity(createError(exception.getMessage(), exception.getMessageDetail())) .build(); @@ -299,7 +299,7 @@ public static Function<InputValidationException, Response> error422InputValidati */ public static Function<ConfigurationInvalidException, Response> error422ConfigurationInvalidMapper() { return exception -> - Response.status(SC_UNPROCESSABLE_ENTITY) + Response.status(SC_UNPROCESSABLE_CONTENT) .header(CONTENT_TYPE, JSON_API_TYPE) .entity(ErrorUtil.createError(exception.getErrors().getFirst().getMessage())) .build(); @@ -317,7 +317,7 @@ public static Function<ConfigurationInvalidException, Response> error422Configur */ public static Function<UcAuthenticationException, Response> error422UcSettingsInvalidMapper() { return exception -> - Response.status(SC_UNPROCESSABLE_ENTITY) + Response.status(SC_UNPROCESSABLE_CONTENT) .header(CONTENT_TYPE, JSON_API_TYPE) .entity(ErrorUtil.createError(exception.getMessage())) .build(); diff --git a/src/main/java/org/folio/rest/util/IdParser.java b/src/main/java/org/folio/rest/util/IdParser.java index 3e76b2a38..1bacef21f 100644 --- a/src/main/java/org/folio/rest/util/IdParser.java +++ b/src/main/java/org/folio/rest/util/IdParser.java @@ -27,32 +27,29 @@ private IdParser() { } public static ResourceId parseResourceId(String id) { - List<Long> parts = parseId(id, 3, RESOURCE_ID_INVALID_ERROR, RESOURCE_ID_INVALID_ERROR); - return ResourceId.builder() - .providerIdPart(parts.get(0)) - .packageIdPart(parts.get(1)) - .titleIdPart(parts.get(2)).build(); + var parts = parseId(id, 3, RESOURCE_ID_INVALID_ERROR, RESOURCE_ID_INVALID_ERROR); + return new ResourceId(parts.get(0), parts.get(1), parts.get(2)); } public static PackageId parsePackageId(String id) { - List<Long> parts = parseId(id, 2, PACKAGE_ID_MISSING_ERROR, PACKAGE_ID_INVALID_ERROR); - return PackageId.builder().providerIdPart(parts.get(0)).packageIdPart(parts.get(1)).build(); + var parts = parseId(id, 2, PACKAGE_ID_MISSING_ERROR, PACKAGE_ID_INVALID_ERROR); + return new PackageId(parts.get(0), parts.get(1)); } - public static Long parseTitleId(String id) { + public static Integer parseTitleId(String id) { return parseId(id, 1, TITLE_ID_IS_INVALID_ERROR, TITLE_ID_IS_INVALID_ERROR).getFirst(); } - public static Long parseProviderId(String id) { + public static Integer parseProviderId(String id) { return parseId(id, 1, INVALID_PROVIDER_ID_ERROR, INVALID_PROVIDER_ID_ERROR).getFirst(); } public static String packageIdToString(PackageId packageId) { - return concat(packageId.getProviderIdPart(), packageId.getPackageIdPart()); + return concat(packageId.providerIdPart(), packageId.packageIdPart()); } public static String resourceIdToString(ResourceId resourceId) { - return concat(resourceId.getProviderIdPart(), resourceId.getPackageIdPart(), resourceId.getTitleIdPart()); + return concat(resourceId.providerIdPart(), resourceId.packageIdPart(), resourceId.titleIdPart()); } public static List<String> resourceIdsToStrings(List<ResourceId> resourceIds) { @@ -72,11 +69,7 @@ public static String getResourceId(HoldingsId holding) { } public static ResourceId getResourceId(DbHoldingInfo resource) { - return ResourceId.builder() - .providerIdPart(resource.getVendorId()) - .packageIdPart(resource.getPackageId()) - .titleIdPart(resource.getTitleId()) - .build(); + return new ResourceId(resource.getVendorId(), resource.getPackageId(), resource.getTitleId()); } public static List<PackageId> getPackageIds(List<DbPackage> packageIds) { @@ -85,10 +78,7 @@ public static List<PackageId> getPackageIds(List<DbPackage> packageIds) { public static List<PackageId> getPackageIds(Packages packages) { return mapItems(packages.getPackagesList(), packageData -> - PackageId.builder() - .packageIdPart(packageData.getPackageId()) - .providerIdPart(packageData.getVendorId()) - .build()); + new PackageId(packageData.getVendorId(), packageData.getPackageId())); } public static List<ResourceId> getTitleIds(List<DbResource> resources) { @@ -103,16 +93,16 @@ private static String concat(long... parts) { return StringUtils.join(parts, '-'); } - private static List<Long> parseId(String id, int partCount, String wrongCountErrorMessage, + private static List<Integer> parseId(String id, int partCount, String wrongCountErrorMessage, String numberFormatErrorMessage) { - String[] parts = id.split("-"); + var parts = id.split("-"); if (parts.length != partCount) { throw new ValidationException(String.format(wrongCountErrorMessage, id)); } - List<Long> parsedParts = new ArrayList<>(); + var parsedParts = new ArrayList<Integer>(); try { for (String part : parts) { - parsedParts.add(Long.parseLong(part)); + parsedParts.add(Integer.parseInt(part)); } return parsedParts; } catch (NumberFormatException e) { diff --git a/src/main/java/org/folio/rest/util/RestConstants.java b/src/main/java/org/folio/rest/util/RestConstants.java index fedaca56a..4e61c9aae 100644 --- a/src/main/java/org/folio/rest/util/RestConstants.java +++ b/src/main/java/org/folio/rest/util/RestConstants.java @@ -2,6 +2,9 @@ import java.util.List; import java.util.Map; +import org.folio.holdingsiq.model.PackageFilterFreeAccess; +import org.folio.holdingsiq.model.PackageFilterSelected; +import org.folio.holdingsiq.model.PackageFilterVisibility; import org.folio.rest.jaxrs.model.JsonAPI; public final class RestConstants { @@ -19,17 +22,29 @@ public final class RestConstants { public static final String TITLE_RECTYPE = "title"; public static final String RESOURCE_RECTYPE = "resource"; - public static final Map<String, String> FILTER_SELECTED_MAPPING = + public static final Map<String, PackageFilterSelected> FILTER_SELECTED_MAPPING = Map.of( - "true", "selected", - "false", "notselected", - "ebsco", "orderedthroughebsco" + "true", PackageFilterSelected.SELECTED, + "false", PackageFilterSelected.NOT_SELECTED, + "ebsco", PackageFilterSelected.ORDERED_THROUGH_EBSCO ); public static final List<String> SUPPORTED_PACKAGE_FILTER_TYPE_VALUES = List.of("all", "aggregatedfulltext", "abstractandindex", "ebook", "ejournal", "print", "unknown", "onlinereference", "streamingmedia", "mixedcontent"); + public static final Map<String, PackageFilterVisibility> FILTER_VISIBILITY_MAPPING = + Map.of("visibleInPF", PackageFilterVisibility.VISIBLE_IN_PF, + "visibleInFTF", PackageFilterVisibility.VISIBLE_IN_FTF, + "visibleInMARC", PackageFilterVisibility.INCLUDED_IN_MARC, + "hiddenInPF", PackageFilterVisibility.HIDDEN_IN_PF, + "hiddenInFTF", PackageFilterVisibility.HIDDEN_IN_FTF, + "hiddenInMARC", PackageFilterVisibility.EXCLUDED_FROM_MARC); + + public static final Map<String, PackageFilterFreeAccess> FILTER_FREE_ACCESS_MAPPING = + Map.of("public", PackageFilterFreeAccess.TRUE, + "controlled", PackageFilterFreeAccess.FALSE); + public static final List<String> SUPPORTED_TITLE_FILTER_TYPE_VALUES = List.of("audiobook", "book", "bookseries", "database", "journal", "newsletter", "newspaper", "proceedings", "report", diff --git a/src/main/java/org/folio/rest/util/template/RmApiTemplate.java b/src/main/java/org/folio/rest/util/template/RmApiTemplate.java index 593f1a74f..8f94f2a11 100644 --- a/src/main/java/org/folio/rest/util/template/RmApiTemplate.java +++ b/src/main/java/org/folio/rest/util/template/RmApiTemplate.java @@ -9,9 +9,9 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Function; import javax.ws.rs.core.Response; -import org.apache.http.HttpStatus; -import org.apache.http.protocol.HTTP; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.HttpHeaders; +import org.folio.HttpStatus; +import org.folio.holdingsiq.model.RequestContext; import org.folio.rest.util.ErrorHandler; import org.folio.rest.validator.HeaderValidator; import org.folio.service.kbcredentials.UserKbCredentialsService; @@ -98,7 +98,7 @@ public <T> void executeWithResult(Class<T> responseClass) { result -> Response .status(HttpStatus.SC_OK) - .header(HTTP.CONTENT_TYPE, JSON_API_TYPE) + .header(HttpHeaders.CONTENT_TYPE, JSON_API_TYPE) .entity(conversionService.convert(result, responseClass)) .build() ); @@ -119,8 +119,8 @@ public CompletableFuture<RmApiTemplateContext> getRmapiTemplateContext() { headerValidator.validate(okapiHeaders); return CompletableFuture.completedFuture(null) .thenCompose(o -> { - OkapiData okapiData = new OkapiData(okapiHeaders); - contextBuilder.okapiData(okapiData); + var requestContext = new RequestContext(okapiHeaders); + contextBuilder.requestContext(requestContext); return userKbCredentialsService.findByUser(okapiHeaders); }) .thenAccept(contextBuilder::kbCredentials) diff --git a/src/main/java/org/folio/rest/util/template/RmApiTemplateContext.java b/src/main/java/org/folio/rest/util/template/RmApiTemplateContext.java index dbdc56324..5af369a58 100644 --- a/src/main/java/org/folio/rest/util/template/RmApiTemplateContext.java +++ b/src/main/java/org/folio/rest/util/template/RmApiTemplateContext.java @@ -3,7 +3,7 @@ import lombok.Builder; import lombok.Value; import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.service.HoldingsIQService; import org.folio.holdingsiq.service.LoadService; import org.folio.rmapi.PackageServiceImpl; @@ -21,7 +21,7 @@ public class RmApiTemplateContext { ResourcesServiceImpl resourcesService; TitlesServiceImpl titlesService; LoadService loadingService; - OkapiData okapiData; + RequestContext requestContext; Configuration configuration; String credentialsId; String credentialsName; diff --git a/src/main/java/org/folio/rest/util/template/RmApiTemplateContextBuilder.java b/src/main/java/org/folio/rest/util/template/RmApiTemplateContextBuilder.java index 8c50798be..1515aedbc 100644 --- a/src/main/java/org/folio/rest/util/template/RmApiTemplateContextBuilder.java +++ b/src/main/java/org/folio/rest/util/template/RmApiTemplateContextBuilder.java @@ -3,8 +3,8 @@ import io.vertx.core.Vertx; import org.folio.cache.VertxCache; import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.OkapiData; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.VendorById; import org.folio.holdingsiq.service.HoldingsIQService; @@ -31,7 +31,7 @@ @SuppressWarnings("java:S6813") public class RmApiTemplateContextBuilder { - private OkapiData okapiData; + private RequestContext requestContext; private KbCredentials credentials; @Autowired @@ -39,7 +39,7 @@ public class RmApiTemplateContextBuilder { @Autowired private VertxCache<VendorCacheKey, VendorById> vendorCache; @Autowired - private VertxCache<PackageCacheKey, PackageByIdData> packageCache; + private VertxCache<PackageCacheKey, PackageData> packageCache; @Autowired private VertxCache<ResourceCacheKey, Title> resourceCache; @Autowired @@ -50,8 +50,8 @@ public class RmApiTemplateContextBuilder { @Autowired private Vertx vertx; - public RmApiTemplateContextBuilder okapiData(OkapiData okapiData) { - this.okapiData = okapiData; + public RmApiTemplateContextBuilder requestContext(RequestContext requestContext) { + this.requestContext = requestContext; return this; } @@ -62,13 +62,13 @@ public RmApiTemplateContextBuilder kbCredentials(KbCredentials credentials) { @SuppressWarnings("checkstyle:MethodLength") public RmApiTemplateContext build() { - String tenant = okapiData.getTenant(); + String tenant = requestContext.getTenant(); Configuration configuration = converter.convert(credentials); final HoldingsIQService holdingsService = new HoldingsIQServiceImpl(configuration, vertx); final TitlesServiceImpl titlesService = - new TitlesServiceImpl(configuration, vertx, okapiData.getTenant(), titleCache); + new TitlesServiceImpl(configuration, vertx, requestContext.getTenant(), titleCache); final ProvidersServiceImpl providersService = new ProvidersServiceImpl(configuration, vertx, tenant, holdingsService, vendorCache); final PackageServiceImpl packagesService = @@ -81,7 +81,7 @@ public RmApiTemplateContext build() { return RmApiTemplateContext.builder() .configuration(configuration) - .okapiData(okapiData) + .requestContext(requestContext) .credentialsId(credentials.getId()) .credentialsName(credentials.getAttributes().getName()) .holdingsService(holdingsService) diff --git a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java b/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java index 9eb8cd1c9..3f06a4121 100644 --- a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java +++ b/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java @@ -1,8 +1,10 @@ package org.folio.rest.validator; +import java.util.List; import org.folio.rest.exception.InputValidationException; import org.folio.rest.jaxrs.model.PackagePutDataAttributes; import org.folio.rest.jaxrs.model.PackagePutRequest; +import org.folio.rest.jaxrs.model.PackageVisibility; import org.springframework.stereotype.Component; @Component @@ -19,7 +21,6 @@ public void validate(PackagePutRequest request) { PackagePutDataAttributes attributes = request.getData().getAttributes(); Boolean allowKbToAddTitles = attributes.getAllowKbToAddTitles(); - Boolean isHidden = attributes.getVisibilityData() != null ? attributes.getVisibilityData().getIsHidden() : null; String beginCoverage = null; String endCoverage = null; if (attributes.getCustomCoverage() != null) { @@ -29,18 +30,19 @@ public void validate(PackagePutRequest request) { String value = attributes.getPackageToken() != null ? attributes.getPackageToken().getValue() : null; - validateNotSelected(attributes, allowKbToAddTitles, isHidden, beginCoverage, endCoverage, value); + validateNotSelected(attributes, allowKbToAddTitles, attributes.getVisibility(), beginCoverage, endCoverage, value); ValidatorUtil.checkMaxLength("value", value, MAX_TOKEN_LENGTH); ValidatorUtil.checkDateValid("beginCoverage", beginCoverage); ValidatorUtil.checkDateValid("endCoverage", endCoverage); } - private void validateNotSelected(PackagePutDataAttributes attributes, Boolean allowKbToAddTitles, Boolean isHidden, - String beginCoverage, String endCoverage, String value) { + private void validateNotSelected(PackagePutDataAttributes attributes, Boolean allowKbToAddTitles, + List<PackageVisibility> visibility, + String beginCoverage, String endCoverage, String value) { Boolean isSelected = attributes.getIsSelected(); if (isSelected == null || !isSelected) { ValidatorUtil.checkFalseOrNull("allowKbToAddTitles", allowKbToAddTitles); - ValidatorUtil.checkFalseOrNull("visibilityData.isHidden", isHidden); + ValidatorUtil.checkIsEmptyCollection("visibility", visibility); ValidatorUtil.checkIsEmpty("customCoverage.beginCoverage", beginCoverage); ValidatorUtil.checkIsEmpty("customCoverage.endCoverage", endCoverage); ValidatorUtil.checkIsNull("packageToken.value", value); diff --git a/src/main/java/org/folio/rest/validator/ResourcePostValidator.java b/src/main/java/org/folio/rest/validator/ResourcePostValidator.java index 7c7f3d5d7..e3418126a 100644 --- a/src/main/java/org/folio/rest/validator/ResourcePostValidator.java +++ b/src/main/java/org/folio/rest/validator/ResourcePostValidator.java @@ -2,7 +2,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.Titles; import org.folio.rest.exception.InputValidationException; @@ -23,7 +23,7 @@ public void validate(ResourcePostRequest request) { ValidatorUtil.checkIsNotBlank("Title Id", attributes.getTitleId()); } - public void validateRelatedObjects(PackageByIdData packageData, Title title, Titles existingTitles) { + public void validateRelatedObjects(PackageData packageData, Title title, Titles existingTitles) { if (BooleanUtils.isNotTrue(packageData.getIsCustom())) { throw new InputValidationException("Invalid PackageId", "Packageid Cannot associate Title with a managed Package"); diff --git a/src/main/java/org/folio/rest/validator/ValidatorUtil.java b/src/main/java/org/folio/rest/validator/ValidatorUtil.java index 29cffd80e..1948876bd 100644 --- a/src/main/java/org/folio/rest/validator/ValidatorUtil.java +++ b/src/main/java/org/folio/rest/validator/ValidatorUtil.java @@ -4,6 +4,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.util.Collection; import java.util.Objects; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -93,6 +94,14 @@ public static void checkIsNull(String paramName, Object value) { } } + public static <T> void checkIsEmptyCollection(String paramName, Collection<T> value) { + if (Objects.nonNull(value) && !value.isEmpty()) { + throw new InputValidationException( + String.format(INVALID_FIELD_FORMAT, paramName), + String.format(MUST_BE_NULL_FORMAT, paramName)); + } + } + public static void checkDateValid(String paramName, String date) { if (!StringUtils.isEmpty(date) && !isDateValid(date)) { throw new InputValidationException( diff --git a/src/main/java/org/folio/rmapi/LocalConfigurationServiceImpl.java b/src/main/java/org/folio/rmapi/LocalConfigurationServiceImpl.java index db41f8e44..f2eef2f02 100644 --- a/src/main/java/org/folio/rmapi/LocalConfigurationServiceImpl.java +++ b/src/main/java/org/folio/rmapi/LocalConfigurationServiceImpl.java @@ -3,7 +3,7 @@ import io.vertx.core.Vertx; import java.util.concurrent.CompletableFuture; import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.service.impl.ConfigurationServiceImpl; import org.folio.rest.jaxrs.model.KbCredentials; import org.folio.service.kbcredentials.UserKbCredentialsService; @@ -22,7 +22,7 @@ public LocalConfigurationServiceImpl(UserKbCredentialsService userKbCredentialsS } @Override - public CompletableFuture<Configuration> retrieveConfiguration(OkapiData okapiData) { - return userKbCredentialsService.findByUser(okapiData.getHeaders()).thenApply(converter::convert); + public CompletableFuture<Configuration> retrieveConfiguration(RequestContext requestContext) { + return userKbCredentialsService.findByUser(requestContext.getHeaders()).thenApply(converter::convert); } } diff --git a/src/main/java/org/folio/rmapi/PackageServiceImpl.java b/src/main/java/org/folio/rmapi/PackageServiceImpl.java index a45632163..37bde47ed 100644 --- a/src/main/java/org/folio/rmapi/PackageServiceImpl.java +++ b/src/main/java/org/folio/rmapi/PackageServiceImpl.java @@ -20,7 +20,6 @@ import org.folio.cache.VertxCache; import org.folio.holdingsiq.model.Configuration; import org.folio.holdingsiq.model.FilterQuery; -import org.folio.holdingsiq.model.PackageByIdData; import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.PackageId; import org.folio.holdingsiq.model.Packages; @@ -42,14 +41,14 @@ public class PackageServiceImpl extends PackagesHoldingsIQServiceImpl { private static final String INCLUDE_RESOURCES_VALUE = "resources"; private final ProvidersServiceImpl providerService; private final TitlesHoldingsIQService titlesService; - private final VertxCache<PackageCacheKey, PackageByIdData> packageCache; + private final VertxCache<PackageCacheKey, PackageData> packageCache; private final SearchProperties searchProperties; private final Configuration configuration; private final String tenantId; public PackageServiceImpl(Configuration config, Vertx vertx, String tenantId, ProvidersServiceImpl providerService, TitlesHoldingsIQService titlesService, - VertxCache<PackageCacheKey, PackageByIdData> packageCache, + VertxCache<PackageCacheKey, PackageData> packageCache, SearchProperties searchProperties) { super(config, vertx); this.providerService = providerService; @@ -66,16 +65,16 @@ public CompletableFuture<PackageResult> retrievePackage(PackageId packageId, Lis public CompletableFuture<PackageResult> retrievePackage(PackageId packageId, List<String> includedObjects, boolean useCache) { - CompletableFuture<PackageByIdData> packageFuture; + CompletableFuture<PackageData> packageFuture; if (useCache) { packageFuture = retrievePackageWithCache(packageId); } else { - packageFuture = retrievePackage(packageId); + packageFuture = retrievePackage(packageId.packageIdPart()); } CompletableFuture<Titles> titlesFuture; if (includedObjects.contains(INCLUDE_RESOURCES_VALUE)) { - titlesFuture = titlesService.retrieveTitles(packageId.getProviderIdPart(), packageId.getPackageIdPart(), + titlesFuture = titlesService.retrieveTitles(packageId.providerIdPart(), packageId.packageIdPart(), FilterQuery.builder().build(), searchProperties.titlesSearchType(), Sort.NAME, 1, 25); } else { titlesFuture = completedFuture(null); @@ -83,7 +82,7 @@ public CompletableFuture<PackageResult> retrievePackage(PackageId packageId, Lis CompletableFuture<VendorResult> vendorFuture; if (includedObjects.contains(INCLUDE_PROVIDER_VALUE)) { - vendorFuture = providerService.retrieveProvider(packageId.getProviderIdPart(), null); + vendorFuture = providerService.retrieveProvider(packageId.providerIdPart(), null); } else { vendorFuture = completedFuture(new VendorResult(null, null)); } @@ -151,13 +150,13 @@ private Packages mapToPackages(List<PackageResult> results) { .build(); } - private CompletableFuture<PackageByIdData> retrievePackageWithCache(PackageId packageId) { + private CompletableFuture<PackageData> retrievePackageWithCache(PackageId packageId) { PackageCacheKey cacheKey = PackageCacheKey.builder() .packageId(IdParser.packageIdToString(packageId)) .rmapiConfiguration(configuration) .tenant(tenantId) .build(); - return packageCache.getValueOrLoad(cacheKey, () -> retrievePackage(packageId)); + return packageCache.getValueOrLoad(cacheKey, () -> retrievePackage(packageId.packageIdPart())); } private interface Result<R, F> { diff --git a/src/main/java/org/folio/rmapi/ProvidersServiceImpl.java b/src/main/java/org/folio/rmapi/ProvidersServiceImpl.java index cf71ca606..b0e001089 100644 --- a/src/main/java/org/folio/rmapi/ProvidersServiceImpl.java +++ b/src/main/java/org/folio/rmapi/ProvidersServiceImpl.java @@ -11,7 +11,10 @@ import lombok.extern.log4j.Log4j2; import org.folio.cache.VertxCache; import org.folio.holdingsiq.model.Configuration; +import org.folio.holdingsiq.model.PackageFilter; import org.folio.holdingsiq.model.Packages; +import org.folio.holdingsiq.model.Pageable; +import org.folio.holdingsiq.model.Sort; import org.folio.holdingsiq.model.Vendor; import org.folio.holdingsiq.model.VendorById; import org.folio.holdingsiq.model.Vendors; @@ -44,11 +47,11 @@ public void setPackagesService(PackagesHoldingsIQService packagesService) { this.packagesService = packagesService; } - public CompletableFuture<VendorResult> retrieveProvider(long id, String include) { + public CompletableFuture<VendorResult> retrieveProvider(int id, String include) { return retrieveProvider(id, include, false); } - public CompletableFuture<VendorResult> retrieveProvider(long id, String include, boolean useCache) { + public CompletableFuture<VendorResult> retrieveProvider(int id, String include, boolean useCache) { CompletableFuture<VendorById> vendorFuture; CompletableFuture<Packages> packagesFuture; @@ -58,7 +61,9 @@ public CompletableFuture<VendorResult> retrieveProvider(long id, String include, vendorFuture = super.retrieveProvider(id); } if (INCLUDE_PACKAGES_VALUE.equalsIgnoreCase(include)) { - packagesFuture = packagesService.retrievePackages(id); + packagesFuture = packagesService.retrievePackages(id, + PackageFilter.builder().build(), + new Pageable(1, 25, Sort.NAME)); } else { packagesFuture = completedFuture(null); } @@ -67,7 +72,7 @@ public CompletableFuture<VendorResult> retrieveProvider(long id, String include, completedFuture(new VendorResult(vendorFuture.join(), packagesFuture.join()))); } - public CompletableFuture<Vendors> retrieveProviders(List<Long> providerIds) { + public CompletableFuture<Vendors> retrieveProviders(List<Integer> providerIds) { Set<CompletableFuture<VendorResult>> futures = providerIds.stream() .map(id -> retrieveProvider(id, "", true)) .collect(Collectors.toSet()); @@ -85,7 +90,7 @@ private Vendors mapToProviders(List<VendorResult> results) { .build(); } - private CompletableFuture<VendorById> retrieveProviderWithCache(long id) { + private CompletableFuture<VendorById> retrieveProviderWithCache(int id) { VendorCacheKey cacheKey = VendorCacheKey.builder() .vendorId(String.valueOf(id)) .rmapiConfiguration(configuration) diff --git a/src/main/java/org/folio/rmapi/ResourcesServiceImpl.java b/src/main/java/org/folio/rmapi/ResourcesServiceImpl.java index 59480e8de..2a7b42511 100644 --- a/src/main/java/org/folio/rmapi/ResourcesServiceImpl.java +++ b/src/main/java/org/folio/rmapi/ResourcesServiceImpl.java @@ -17,7 +17,7 @@ import org.folio.cache.VertxCache; import org.folio.holdingsiq.model.Configuration; import org.folio.holdingsiq.model.CustomerResources; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.PackageId; import org.folio.holdingsiq.model.ResourceId; import org.folio.holdingsiq.model.Title; @@ -93,8 +93,8 @@ public CompletableFuture<ResourceBulkResult> retrieveResourcesBulk(Set<String> r retrieveResource(resourceId, Collections.emptyList(), true) .whenComplete((result, throwable) -> { if (throwable != null) { - failed.add(resourceId.getProviderIdPart() + "-" + resourceId.getPackageIdPart() + "-" - + resourceId.getTitleIdPart()); + failed.add(resourceId.providerIdPart() + "-" + resourceId.packageIdPart() + "-" + + resourceId.titleIdPart()); } })) .collect(Collectors.toSet()); @@ -103,13 +103,11 @@ public CompletableFuture<ResourceBulkResult> retrieveResourcesBulk(Set<String> r .thenApply(resourceFutures -> mapToResources(resourceFutures, failed)); } - private CompletableFuture<PackageByIdData> retrievePackage(ResourceId resourceId, + private CompletableFuture<PackageData> retrievePackage(ResourceId resourceId, List<String> includes) { if (includes.contains(INCLUDE_PACKAGE_VALUE)) { - PackageId id = PackageId.builder() - .providerIdPart(resourceId.getProviderIdPart()) - .packageIdPart(resourceId.getPackageIdPart()).build(); - return packagesService.retrievePackage(id); + PackageId id = new PackageId(resourceId.providerIdPart(), resourceId.packageIdPart()); + return packagesService.retrievePackage(id.packageIdPart()); } return completedFuture(null); } @@ -117,7 +115,7 @@ private CompletableFuture<PackageByIdData> retrievePackage(ResourceId resourceId private CompletableFuture<VendorResult> retrieveVendor(ResourceId resourceId, List<String> includes) { if (includes.contains(INCLUDE_PROVIDER_VALUE)) { - return providerService.retrieveProvider(resourceId.getProviderIdPart(), ""); + return providerService.retrieveProvider(resourceId.providerIdPart(), ""); } return completedFuture(new VendorResult(null, null)); } diff --git a/src/main/java/org/folio/rmapi/TitlesServiceImpl.java b/src/main/java/org/folio/rmapi/TitlesServiceImpl.java index aed3533f9..faec2420a 100644 --- a/src/main/java/org/folio/rmapi/TitlesServiceImpl.java +++ b/src/main/java/org/folio/rmapi/TitlesServiceImpl.java @@ -32,14 +32,14 @@ public TitlesServiceImpl(Configuration config, Vertx vertx, } @Override - public CompletableFuture<Title> retrieveTitle(long titleId) { + public CompletableFuture<Title> retrieveTitle(int titleId) { var titleFuture = super.retrieveTitle(titleId); var cacheKey = buildTitleCacheKey(titleId); titleFuture.thenAccept(title -> titleCache.putValue(cacheKey, title)); return titleFuture; } - public CompletableFuture<Title> retrieveTitle(long titleId, boolean useCache) { + public CompletableFuture<Title> retrieveTitle(int titleId, boolean useCache) { CompletableFuture<Title> titleFuture; if (useCache) { titleFuture = retrieveTitleWithCache(titleId); @@ -49,7 +49,7 @@ public CompletableFuture<Title> retrieveTitle(long titleId, boolean useCache) { return titleFuture; } - public CompletableFuture<Titles> retrieveTitles(List<Long> titleIds) { + public CompletableFuture<Titles> retrieveTitles(List<Integer> titleIds) { Set<CompletableFuture<Title>> futures = titleIds.stream() .map(id -> retrieveTitle(id, true)) .collect(Collectors.toSet()); @@ -66,9 +66,15 @@ public void updateCache(Title title) { titleCache.putValue(cacheKey, title); } - private CompletableFuture<Title> retrieveTitleWithCache(long titleId) { + private CompletableFuture<Title> retrieveTitleWithCache(int titleId) { var cacheKey = buildTitleCacheKey(titleId); - return titleCache.getValueOrLoad(cacheKey, () -> super.retrieveTitle(titleId)); + return titleCache.getValueOrLoad(cacheKey, () -> { + log.info("Title not found in cache, retrieving from HoldingsIQ"); + return super.retrieveTitle(titleId); + }).handle((title, throwable) -> { + log.info("Title fetched from cache: " + title); + return title; + }); } private void mergeCustomerResources(Title cachedTitle, Title title) { @@ -94,7 +100,7 @@ private Titles mapToTitles(List<Title> titles) { .build(); } - private TitleCacheKey buildTitleCacheKey(long titleId) { + private TitleCacheKey buildTitleCacheKey(int titleId) { return TitleCacheKey.builder() .titleId(titleId) .rmapiConfiguration(configuration) diff --git a/src/main/java/org/folio/rmapi/result/ObjectsForPostResourceResult.java b/src/main/java/org/folio/rmapi/result/ObjectsForPostResourceResult.java index 65e35fd00..ca7110c5f 100644 --- a/src/main/java/org/folio/rmapi/result/ObjectsForPostResourceResult.java +++ b/src/main/java/org/folio/rmapi/result/ObjectsForPostResourceResult.java @@ -1,7 +1,7 @@ package org.folio.rmapi.result; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.Titles; -public record ObjectsForPostResourceResult(Title title, PackageByIdData packageData, Titles titles) { } +public record ObjectsForPostResourceResult(Title title, PackageData packageData, Titles titles) { } diff --git a/src/main/java/org/folio/rmapi/result/PackageResult.java b/src/main/java/org/folio/rmapi/result/PackageResult.java index 375bf0997..c5df952e0 100644 --- a/src/main/java/org/folio/rmapi/result/PackageResult.java +++ b/src/main/java/org/folio/rmapi/result/PackageResult.java @@ -2,7 +2,7 @@ import lombok.Getter; import lombok.Setter; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.model.VendorById; import org.folio.rest.jaxrs.model.AccessType; @@ -12,17 +12,17 @@ @Setter public class PackageResult implements Accessible, Tagable { - private PackageByIdData packageData; + private PackageData packageData; private VendorById vendor; private Titles titles; private Tags tags; private AccessType accessType; - public PackageResult(PackageByIdData packageData) { + public PackageResult(PackageData packageData) { this.packageData = packageData; } - public PackageResult(PackageByIdData packageData, VendorById vendor, Titles titles) { + public PackageResult(PackageData packageData, VendorById vendor, Titles titles) { this.packageData = packageData; this.vendor = vendor; this.titles = titles; diff --git a/src/main/java/org/folio/rmapi/result/ResourceResult.java b/src/main/java/org/folio/rmapi/result/ResourceResult.java index d57510575..43fc9f0e2 100644 --- a/src/main/java/org/folio/rmapi/result/ResourceResult.java +++ b/src/main/java/org/folio/rmapi/result/ResourceResult.java @@ -2,7 +2,7 @@ import lombok.Getter; import lombok.Setter; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.VendorById; import org.folio.rest.jaxrs.model.AccessType; @@ -14,12 +14,12 @@ public class ResourceResult implements Accessible, Tagable { private Title title; private VendorById vendor; - private PackageByIdData packageData; + private PackageData packageData; private boolean includeTitle; private Tags tags; private AccessType accessType; - public ResourceResult(Title title, VendorById vendor, PackageByIdData packageData, boolean includeTitle) { + public ResourceResult(Title title, VendorById vendor, PackageData packageData, boolean includeTitle) { this.title = title; this.vendor = vendor; this.packageData = packageData; diff --git a/src/main/java/org/folio/service/accesstypes/AccessTypesServiceImpl.java b/src/main/java/org/folio/service/accesstypes/AccessTypesServiceImpl.java index 84135e9f1..86b6f34c8 100644 --- a/src/main/java/org/folio/service/accesstypes/AccessTypesServiceImpl.java +++ b/src/main/java/org/folio/service/accesstypes/AccessTypesServiceImpl.java @@ -6,6 +6,7 @@ import static org.folio.db.RowSetUtils.toUUID; import static org.folio.rest.util.RequestHeadersUtil.tenantId; +import java.time.Clock; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; @@ -22,8 +23,8 @@ import javax.ws.rs.BadRequestException; import javax.ws.rs.NotFoundException; import lombok.extern.log4j.Log4j2; -import org.folio.common.OkapiParams; import org.folio.db.exc.DbExcUtils; +import org.folio.holdingsiq.model.RequestContext; import org.folio.repository.RecordKey; import org.folio.repository.RecordType; import org.folio.repository.accesstypes.AccessTypesRepository; @@ -170,7 +171,7 @@ public CompletableFuture<AccessType> save(String credentialsId, AccessTypePostRe .thenApply(dbAccessType -> prePopulateCreatorMetadata(dbAccessType, okapiHeaders)) .thenCompose(dbAccessType -> repository.save(dbAccessType, tenantId(okapiHeaders))) .thenApply(accessTypeFromDbConverter::convert) - .thenCombine(usersLookUpService.lookUpUser(new OkapiParams(okapiHeaders)), this::setCreatorMetaInfo); + .thenCombine(usersLookUpService.lookUpUser(new RequestContext(okapiHeaders)), this::setCreatorMetaInfo); } @Override @@ -223,14 +224,14 @@ public CompletionStage<Map<String, DbAccessType>> findPerRecord(String credentia private DbAccessType prePopulateCreatorMetadata(DbAccessType dbAccessType, Map<String, String> okapiHeaders) { return dbAccessType.toBuilder() .createdByUserId(UUID.fromString(RequestHeadersUtil.userId(okapiHeaders))) - .createdDate(OffsetDateTime.now()) + .createdDate(OffsetDateTime.now(Clock.systemDefaultZone())) .build(); } private DbAccessType prePopulateUpdaterMetadata(DbAccessType dbAccessType, Map<String, String> okapiHeaders) { return dbAccessType.toBuilder() .updatedByUserId(UUID.fromString(RequestHeadersUtil.userId(okapiHeaders))) - .updatedDate(OffsetDateTime.now()) + .updatedDate(OffsetDateTime.now(Clock.systemDefaultZone())) .build(); } @@ -244,7 +245,7 @@ private CompletableFuture<List<AccessType>> populateUserMetadata(Map<String, Str .distinct() .map(UUID::fromString) .toList(); - return usersLookUpService.lookUpUsers(usersIds, new OkapiParams(okapiHeaders)) + return usersLookUpService.lookUpUsers(usersIds, new RequestContext(okapiHeaders)) .thenApply(users -> users.stream().collect(Collectors.toMap(User::getId, u -> u))) .thenApply(usersMap -> enrichAccessTypes(accessTypes, usersMap)); } diff --git a/src/main/java/org/folio/service/assignedusers/AssignedUsersServiceImpl.java b/src/main/java/org/folio/service/assignedusers/AssignedUsersServiceImpl.java index 6c99a103e..c7bd2c7a3 100644 --- a/src/main/java/org/folio/service/assignedusers/AssignedUsersServiceImpl.java +++ b/src/main/java/org/folio/service/assignedusers/AssignedUsersServiceImpl.java @@ -15,7 +15,7 @@ import java.util.function.Function; import javax.ws.rs.NotFoundException; import lombok.extern.log4j.Log4j2; -import org.folio.common.OkapiParams; +import org.folio.holdingsiq.model.RequestContext; import org.folio.repository.assigneduser.AssignedUserRepository; import org.folio.repository.assigneduser.DbAssignedUser; import org.folio.rest.converter.assignedusers.UserCollectionDataConverter; @@ -63,7 +63,7 @@ public CompletableFuture<AssignedUserCollection> findByCredentialsId(String cred .map(DbAssignedUser::getId) .toList()) .thenCompose(idBatches -> loadInBatches(idBatches, - idBatch -> usersLookUpService.lookUpUsers(idBatch, new OkapiParams(okapiHeaders)))) + idBatch -> usersLookUpService.lookUpUsers(idBatch, new RequestContext(okapiHeaders)))) .thenCompose(users -> CompletableFuture.completedFuture(sortByLastName(users)) .thenCombine(fetchGroups(users, okapiHeaders), UserCollectionDataConverter.UsersResult::new) .thenApply(userCollectionConverter::convert)); @@ -74,7 +74,7 @@ public CompletableFuture<AssignedUserId> save(AssignedUserId assignedUserId, Map String tenantId = tenantId(okapiHeaders); log.debug("save:: by [assignedUserId: {}, tenant: {}]", assignedUserId, tenantId); - return usersLookUpService.lookUpUserById(assignedUserId.getId(), new OkapiParams(okapiHeaders)) + return usersLookUpService.lookUpUserById(assignedUserId.getId(), new RequestContext(okapiHeaders)) .exceptionally(throwable -> { if (throwable instanceof NotFoundException) { throw new InputValidationException("Unable to assign user", "User doesn't exist"); @@ -122,6 +122,6 @@ private CompletableFuture<List<Group>> fetchGroups(Collection<User> users, Map<S .distinct() .toList(); return loadInBatches(groupIds, - idBatch -> usersLookUpService.lookUpGroups(idBatch, new OkapiParams(okapiHeaders))); + idBatch -> usersLookUpService.lookUpGroups(idBatch, new RequestContext(okapiHeaders))); } } diff --git a/src/main/java/org/folio/service/holdings/HoldingsServiceImpl.java b/src/main/java/org/folio/service/holdings/HoldingsServiceImpl.java index 966eaee7d..e1c3b7e34 100644 --- a/src/main/java/org/folio/service/holdings/HoldingsServiceImpl.java +++ b/src/main/java/org/folio/service/holdings/HoldingsServiceImpl.java @@ -129,7 +129,7 @@ public HoldingsServiceImpl(Vertx vertx, HoldingsRepository holdingsRepository, @Override public CompletableFuture<Void> loadSingleHoldings(RmApiTemplateContext context) { - final String tenantId = context.getOkapiData().getTenant(); + final String tenantId = context.getRequestContext().getTenant(); final String credentialsId = context.getCredentialsId(); log.debug("loadSingleHoldings:: by [tenant: {}]", tenantId); diff --git a/src/main/java/org/folio/service/kbcredentials/KbCredentialsServiceImpl.java b/src/main/java/org/folio/service/kbcredentials/KbCredentialsServiceImpl.java index b6b44f416..f5fbe6fe7 100644 --- a/src/main/java/org/folio/service/kbcredentials/KbCredentialsServiceImpl.java +++ b/src/main/java/org/folio/service/kbcredentials/KbCredentialsServiceImpl.java @@ -17,7 +17,7 @@ import java.util.function.Function; import lombok.extern.log4j.Log4j2; import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.service.ConfigurationService; import org.folio.holdingsiq.service.exception.ConfigurationInvalidException; import org.folio.repository.kbcredentials.DbKbCredentials; @@ -167,10 +167,10 @@ private DbKbCredentials prepareUpdateEntity(DbKbCredentials existingCredentials, private CompletableFuture<DbKbCredentials> prepareAndSave( CompletableFuture<DbKbCredentials> credentialsFuture, BiFunction<DbKbCredentials, String, DbKbCredentials> prepareEntityFn, - Map<String, String> okapiHeaders) { + Map<String, String> headers) { return credentialsFuture - .thenCombine(RequestHeadersUtil.userIdFuture(okapiHeaders), prepareEntityFn) - .thenCompose(dbKbCredentials -> verifyAndSave(dbKbCredentials, okapiHeaders)); + .thenCombine(RequestHeadersUtil.userIdFuture(headers), prepareEntityFn) + .thenCompose(dbKbCredentials -> verifyAndSave(dbKbCredentials, headers)); } private DbKbCredentials prepareSaveEntity(DbKbCredentials dbKbCredentials, String userId) { @@ -181,19 +181,19 @@ private DbKbCredentials prepareSaveEntity(DbKbCredentials dbKbCredentials, Strin } private CompletableFuture<DbKbCredentials> verifyAndSave(DbKbCredentials dbKbCredentials, - Map<String, String> okapiHeaders) { + Map<String, String> headers) { - String tenantId = tenantId(okapiHeaders); + String tenantId = tenantId(headers); log.info("verifyAndSave:: Attempting to save by [id: {}, tenant: {}]", fromUUID(dbKbCredentials.getId()), tenantId); - return verifyCredentials(dbKbCredentials, okapiHeaders) + return verifyCredentials(dbKbCredentials, headers) .thenCompose(v -> repository.save(dbKbCredentials, tenantId)); } - private CompletableFuture<Void> verifyCredentials(DbKbCredentials dbKbCredentials, Map<String, String> okapiHeaders) { + private CompletableFuture<Void> verifyCredentials(DbKbCredentials dbKbCredentials, Map<String, String> headers) { Configuration configuration = convertToConfiguration(dbKbCredentials); - return configurationService.verifyCredentials(configuration, context, new OkapiData(okapiHeaders)) + return configurationService.verifyCredentials(configuration, context, new RequestContext(headers)) .thenCompose(errors -> { if (!errors.isEmpty()) { CompletableFuture<Void> future = new CompletableFuture<>(); diff --git a/src/main/java/org/folio/service/loader/FilteredEntitiesLoaderImpl.java b/src/main/java/org/folio/service/loader/FilteredEntitiesLoaderImpl.java index e90b3783a..739a861cb 100644 --- a/src/main/java/org/folio/service/loader/FilteredEntitiesLoaderImpl.java +++ b/src/main/java/org/folio/service/loader/FilteredEntitiesLoaderImpl.java @@ -95,7 +95,7 @@ public CompletableFuture<Packages> fetchPackagesByAccessTypeFilter(AccessTypeFil @Override public CompletableFuture<ResourceCollectionResult> fetchResourcesByAccessTypeFilter(AccessTypeFilter accessTypeFilter, RmApiTemplateContext context) { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); AtomicInteger totalCount = new AtomicInteger(); return fetchAccessTypeMappings(accessTypeFilter, context, totalCount) .thenApply(this::extractResourceIds) @@ -128,7 +128,7 @@ public CompletableFuture<Titles> fetchTitlesByAccessTypeFilter(AccessTypeFilter @Override public CompletableFuture<Vendors> fetchProvidersByTagFilter(TagFilter tagFilter, RmApiTemplateContext context) { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); UUID credentialsId = toUUID(context.getCredentialsId()); ProvidersServiceImpl providersService = context.getProvidersService(); log.debug("fetchProvidersByTagFilter:: by [recordIdPrefix: {}, tenant: {}]", @@ -144,7 +144,7 @@ public CompletableFuture<Vendors> fetchProvidersByTagFilter(TagFilter tagFilter, @Override public CompletableFuture<PackageCollectionResult> fetchPackagesByTagFilter(TagFilter tagFilter, RmApiTemplateContext context) { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); UUID credentialsId = toUUID(context.getCredentialsId()); PackageServiceImpl packagesService = context.getPackagesService(); log.debug("fetchPackagesByTagFilter:: by [recordIdPrefix: {}, tenant: {}]", @@ -161,7 +161,7 @@ public CompletableFuture<PackageCollectionResult> fetchPackagesByTagFilter(TagFi @Override public CompletableFuture<ResourceCollectionResult> fetchResourcesByTagFilter(TagFilter tagFilter, RmApiTemplateContext context) { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); UUID credentialsId = toUUID(context.getCredentialsId()); log.debug("fetchResourcesByTagFilter:: by [recordIdPrefix: {}. tenant: {}]", tagFilter.getRecordIdPrefix(), tenant); @@ -182,7 +182,7 @@ public CompletableFuture<ResourceCollectionResult> fetchResourcesByTagFilter(Tag @Override public CompletableFuture<Titles> fetchTitlesByTagFilter(TagFilter tagFilter, RmApiTemplateContext context) { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); UUID credentialsId = toUUID(context.getCredentialsId()); log.debug("fetchTitlesByTagFilter:: by [recordIdPrefix: {}. tenant: {}]", tagFilter.getRecordIdPrefix(), tenant); @@ -236,7 +236,7 @@ private List<ResourceId> getMissingResourceIds(List<DbHoldingInfo> holdings, Lis private CompletableFuture<Collection<AccessTypeMapping>> fetchAccessTypeMappings(AccessTypeFilter accessTypeFilter, RmApiTemplateContext context, AtomicInteger totalCount) { - Map<String, String> okapiHeaders = context.getOkapiData().getHeaders(); + Map<String, String> okapiHeaders = context.getRequestContext().getHeaders(); String credentialsId = context.getCredentialsId(); RecordType recordType = accessTypeFilter.getRecordType(); String recordIdPrefix = createRecordIdPrefix(accessTypeFilter); @@ -277,19 +277,19 @@ private List<PackageId> extractPackageIds(Collection<AccessTypeMapping> accessTy .collect(Collectors.toCollection(ArrayList::new)); } - private List<Long> extractTitleIds(Collection<AccessTypeMapping> accessTypeMappings) { + private List<Integer> extractTitleIds(Collection<AccessTypeMapping> accessTypeMappings) { return accessTypeMappings.stream() .map(AccessTypeMapping::getRecordId) .map(IdParser::parseResourceId) - .map(ResourceId::getTitleIdPart) + .map(ResourceId::titleIdPart) .distinct() .collect(Collectors.toCollection(ArrayList::new)); } - private List<Long> extractTitleIds(List<DbResource> dbResources) { + private List<Integer> extractTitleIds(List<DbResource> dbResources) { return dbResources.stream() .map(DbResource::getId) - .map(ResourceId::getTitleIdPart) + .map(ResourceId::titleIdPart) .distinct() .collect(Collectors.toCollection(ArrayList::new)); } diff --git a/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java b/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java index 3d457c509..b4b1ccff5 100644 --- a/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java +++ b/src/main/java/org/folio/service/loader/RelatedEntitiesLoaderImpl.java @@ -36,7 +36,7 @@ public CompletableFuture<Void> loadAccessType(Accessible accessible, RecordKey r log.debug("loadAccessType:: by [recordKey: {}]", recordKey); CompletableFuture<Void> future = new CompletableFuture<>(); - accessTypesService.findByRecord(recordKey, context.getCredentialsId(), context.getOkapiData().getHeaders()) + accessTypesService.findByRecord(recordKey, context.getCredentialsId(), context.getRequestContext().getHeaders()) .whenComplete((accessType, throwable) -> { if (throwable != null && !(throwable.getCause() instanceof NotFoundException)) { future.completeExceptionally(throwable.getCause()); @@ -50,7 +50,7 @@ public CompletableFuture<Void> loadAccessType(Accessible accessible, RecordKey r @Override public CompletableFuture<Void> loadTags(Tagable tagable, RecordKey recordKey, RmApiTemplateContext context) { - String tenant = context.getOkapiData().getTenant(); + String tenant = context.getRequestContext().getTenant(); log.debug("loadTags:: by [recordKey: {}, tenant: {}]", recordKey, tenant); return tagRepository.findByRecord(tenant, recordKey.getRecordId(), diff --git a/src/main/java/org/folio/service/locale/LocaleSettingsService.java b/src/main/java/org/folio/service/locale/LocaleSettingsService.java index ad32f66eb..1745d0eff 100644 --- a/src/main/java/org/folio/service/locale/LocaleSettingsService.java +++ b/src/main/java/org/folio/service/locale/LocaleSettingsService.java @@ -1,9 +1,9 @@ package org.folio.service.locale; import java.util.concurrent.CompletableFuture; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; public interface LocaleSettingsService { - CompletableFuture<LocaleSettings> retrieveSettings(OkapiData okapiData); + CompletableFuture<LocaleSettings> retrieveSettings(RequestContext requestContext); } diff --git a/src/main/java/org/folio/service/locale/LocaleSettingsServiceImpl.java b/src/main/java/org/folio/service/locale/LocaleSettingsServiceImpl.java index dbc41f6fb..678601b2c 100644 --- a/src/main/java/org/folio/service/locale/LocaleSettingsServiceImpl.java +++ b/src/main/java/org/folio/service/locale/LocaleSettingsServiceImpl.java @@ -13,7 +13,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import lombok.extern.log4j.Log4j2; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.rest.tools.utils.VertxUtils; import org.jspecify.annotations.NonNull; @@ -22,10 +22,10 @@ public class LocaleSettingsServiceImpl implements LocaleSettingsService { public static final String LOCALE_ENDPOINT_PATH = "/locale"; - public CompletableFuture<LocaleSettings> retrieveSettings(OkapiData okapiData) { + public CompletableFuture<LocaleSettings> retrieveSettings(RequestContext requestContext) { log.debug("Retrieving locale settings"); - return retrieveLocaleSettings(okapiData) + return retrieveLocaleSettings(requestContext) .thenApply(this::mapToLocaleSettings) .exceptionally(throwable -> { log.warn("Locale settings retrieval failed, falling back to default", throwable); @@ -41,14 +41,14 @@ public CompletableFuture<LocaleSettings> retrieveSettings(OkapiData okapiData) { }); } - private CompletableFuture<JsonObject> retrieveLocaleSettings(OkapiData okapiData) { + private CompletableFuture<JsonObject> retrieveLocaleSettings(RequestContext requestContext) { CompletableFuture<JsonObject> future = new CompletableFuture<>(); WebClient webClient = null; try { log.debug("Sending request to GET {}", LOCALE_ENDPOINT_PATH); webClient = prepareConfigurationsClient(); - var request = prepareRequest(okapiData, webClient); + var request = prepareRequest(requestContext, webClient); WebClient finalWebClient = webClient; request.send() @@ -72,9 +72,9 @@ private Handler<Throwable> handleFailure(CompletableFuture<JsonObject> future, W }; } - private HttpRequest<Buffer> prepareRequest(OkapiData okapiData, WebClient webClient) { - var request = webClient.requestAbs(HttpMethod.GET, okapiData.getOkapiUrl() + LOCALE_ENDPOINT_PATH); - okapiData.getHeaders().forEach(request::putHeader); + private HttpRequest<Buffer> prepareRequest(RequestContext requestContext, WebClient webClient) { + var request = webClient.requestAbs(HttpMethod.GET, requestContext.getUrl() + LOCALE_ENDPOINT_PATH); + requestContext.getHeaders().forEach(request::putHeader); request.putHeader("Accept", "application/json,text/plain"); return request; } diff --git a/src/main/java/org/folio/service/uc/UcCostPerUseServiceImpl.java b/src/main/java/org/folio/service/uc/UcCostPerUseServiceImpl.java index 9ad9b511f..2fa304202 100644 --- a/src/main/java/org/folio/service/uc/UcCostPerUseServiceImpl.java +++ b/src/main/java/org/folio/service/uc/UcCostPerUseServiceImpl.java @@ -198,7 +198,7 @@ private CompletableFuture<ResourceCostPerUseCollectionResult> fetchHoldings(Stri packageId, platform, fiscalYear); validateParams(platform, fiscalYear, sort); var id = parsePackageId(packageId); - var packageIdPart = valueOf(id.getPackageIdPart()); + var packageIdPart = valueOf(id.packageIdPart()); MutableObject<PlatformType> platformTypeHolder = new MutableObject<>(); return templateFactory.createTemplate(okapiHeaders, Promise.promise()).getRmapiTemplateContext() @@ -212,7 +212,7 @@ private CompletableFuture<PackageCostPerUseResult> composePackageCostPerUseResul String packageId, PlatformType platformType, RmApiTemplateContext context, CommonUcConfiguration ucConfiguration) { - var packageIdPart = valueOf(parsePackageId(packageId).getPackageIdPart()); + var packageIdPart = valueOf(parsePackageId(packageId).packageIdPart()); log.info("composePackageCostPerUseResult:: Composing Result for Package Cost Per use with packageIdPart: {}, " + "platformType: {}", packageIdPart, platformType); return client.getPackageCostPerUse(packageIdPart, createGetPackageConfiguration(ucConfiguration)) @@ -384,7 +384,7 @@ private UcCostAnalysis toAllPublisherUcCostAnalysis(UcCostAnalysis ucCostAnalysi private CompletableFuture<List<DbHoldingInfo>> fetchHoldingsData(String packageIdPart, RmApiTemplateContext context) { log.info("fetchHoldingsData:: Get Holdings data by packageId: {} ", packageIdPart); return holdingsService - .getHoldingsByPackageId(packageIdPart, context.getCredentialsId(), context.getOkapiData().getTenant()); + .getHoldingsByPackageId(packageIdPart, context.getCredentialsId(), context.getRequestContext().getTenant()); } private CompletableFuture<CommonUcConfiguration> fetchCommonConfiguration( @@ -401,7 +401,7 @@ private CompletableFuture<CommonUcConfiguration> fetchCommonConfiguration( String platform, String fiscalYear, MutableObject<PlatformType> platformTypeHolder, RmApiTemplateContext context) { - Map<String, String> okapiHeaders = context.getOkapiData().getHeaders(); + Map<String, String> okapiHeaders = context.getRequestContext().getHeaders(); return authService.authenticate(okapiHeaders) .thenCombine(settingsService.fetchByCredentialsId(context.getCredentialsId(), false, okapiHeaders), toCommonUcConfiguration(platform, fiscalYear, platformTypeHolder) @@ -465,8 +465,8 @@ private List<UcTitlePackageId> extractTitlePackageIds(List<DbHoldingInfo> dbHold private CompletableFuture<UcTitleCostPerUse> getTitleCost(ResourceId id, GetTitleUcConfiguration configuration) { log.info("getTitleCost:: Get by titleId: {}, packageId: {} and configurations", - id.getTitleIdPart(), id.getPackageIdPart()); - return client.getTitleCostPerUse(valueOf(id.getTitleIdPart()), valueOf(id.getPackageIdPart()), configuration); + id.titleIdPart(), id.packageIdPart()); + return client.getTitleCostPerUse(valueOf(id.titleIdPart()), valueOf(id.packageIdPart()), configuration); } private CommonUcConfiguration createCommonConfiguration(UCSettings ucSettings, String fiscalYear, String authToken) { diff --git a/src/main/java/org/folio/service/uc/export/ExportServiceImpl.java b/src/main/java/org/folio/service/uc/export/ExportServiceImpl.java index 83fa37425..92767e46b 100644 --- a/src/main/java/org/folio/service/uc/export/ExportServiceImpl.java +++ b/src/main/java/org/folio/service/uc/export/ExportServiceImpl.java @@ -12,7 +12,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import lombok.extern.log4j.Log4j2; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.rest.converter.costperuse.export.PackageTitlesCostPerUseCollectionToExportConverter; import org.folio.service.locale.LocaleSettingsService; import org.folio.service.uc.UcCostPerUseService; @@ -34,10 +34,10 @@ public ExportServiceImpl(UcCostPerUseService costPerUseService, LocaleSettingsSe } public CompletableFuture<String> exportCsv(String packageId, String platform, String year, - Map<String, String> okapiHeaders) { + Map<String, String> headers) { log.info("Perform export for package - {}", packageId); - return costPerUseService.getPackageResourcesCostPerUse(packageId, platform, year, okapiHeaders) - .thenCombine(localeSettingsService.retrieveSettings(new OkapiData(okapiHeaders)), + return costPerUseService.getPackageResourcesCostPerUse(packageId, platform, year, headers) + .thenCombine(localeSettingsService.retrieveSettings(new RequestContext(headers)), (collection, localeSettings) -> converter.convert(collection, platform, year, localeSettings)) .thenCompose(this::mapToCsv); } diff --git a/src/main/java/org/folio/service/uc/export/TitleExportModel.java b/src/main/java/org/folio/service/uc/export/TitleExportModel.java index fc3456065..ab602f33e 100644 --- a/src/main/java/org/folio/service/uc/export/TitleExportModel.java +++ b/src/main/java/org/folio/service/uc/export/TitleExportModel.java @@ -19,7 +19,7 @@ public class TitleExportModel { @CsvBindByName(column = "Usage") @CsvBindByPosition(position = 2) - private final int usage; + private final long usage; @CsvBindByName(column = "Cost") @CsvBindByPosition(position = 3) diff --git a/src/main/java/org/folio/service/users/UsersLookUpService.java b/src/main/java/org/folio/service/users/UsersLookUpService.java index 15e4a81e2..8abd3be4a 100644 --- a/src/main/java/org/folio/service/users/UsersLookUpService.java +++ b/src/main/java/org/folio/service/users/UsersLookUpService.java @@ -23,8 +23,8 @@ import javax.ws.rs.NotFoundException; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpHeaders; -import org.folio.common.OkapiParams; +import org.folio.HttpHeaders; +import org.folio.holdingsiq.model.RequestContext; import org.folio.okapi.common.XOkapiHeaders; import org.folio.rest.util.RequestHeadersUtil; import org.folio.util.StringUtil; @@ -38,11 +38,12 @@ @Log4j2 @Component public class UsersLookUpService { - private static final String USERS_ENDPOINT_TEMPLATE = "/users/%s"; - private static final String USERS_ENDPOINT = "/users"; - private static final String GROUPS_ENDPOINT = "/groups"; - private static final String CQL_QUERY_PARAM = "query"; + public static final String USERS_ENDPOINT = "/users"; + public static final String USERS_BY_ID_ENDPOINT = USERS_ENDPOINT + "/%s"; + public static final String GROUPS_ENDPOINT = "/groups"; + public static final String CQL_QUERY_PARAM = "query"; + private static final String LIMIT_PARAM = "limit"; private static final String AUTHORIZATION_FAIL_ERROR_MESSAGE = "Authorization failure"; private static final String USER_NOT_FOUND_ERROR_MESSAGE = "User not found"; @@ -58,15 +59,15 @@ public UsersLookUpService(@Autowired Vertx vertx) { /** * Returns the user information for the userid specified in X-Okapi-Token. * - * @param okapiParams The okapi params for the current API call. + * @param requestCtx The okapi params for the current API call. * @return User information. */ - public CompletableFuture<User> lookUpUser(final OkapiParams okapiParams) { + public CompletableFuture<User> lookUpUser(final RequestContext requestCtx) { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); - headers.addAll(okapiParams.getHeaders()); + headers.addAll(requestCtx.getHeaders()); headers.add(HttpHeaders.ACCEPT, HttpHeaderValues.APPLICATION_JSON); - return RequestHeadersUtil.userIdFuture(okapiParams.getHeaders()) + return RequestHeadersUtil.userIdFuture(requestCtx.getHeaders()) .thenCompose(userId -> { Promise<HttpResponse<JsonObject>> promise = Promise.promise(); sendUserRequest(userId, headers, promise); @@ -74,23 +75,23 @@ public CompletableFuture<User> lookUpUser(final OkapiParams okapiParams) { }); } - public CompletableFuture<List<User>> lookUpUsers(List<UUID> ids, final OkapiParams okapiParams) { + public CompletableFuture<List<User>> lookUpUsers(List<UUID> ids, final RequestContext requestCtx) { if (ids.isEmpty()) { return CompletableFuture.completedFuture(emptyList()); } - return lookUpUsersUsingCql(getIdsCql(ids), ids.size(), okapiParams); + return lookUpUsersUsingCql(getIdsCql(ids), ids.size(), requestCtx); } - public CompletableFuture<List<Group>> lookUpGroups(List<UUID> ids, final OkapiParams okapiParams) { + public CompletableFuture<List<Group>> lookUpGroups(List<UUID> ids, final RequestContext requestCtx) { if (ids.isEmpty()) { return CompletableFuture.completedFuture(emptyList()); } - return lookUpGroupsUsingCql(getIdsCql(ids), ids.size(), okapiParams); + return lookUpGroupsUsingCql(getIdsCql(ids), ids.size(), requestCtx); } - public CompletableFuture<User> lookUpUserById(String userId, OkapiParams okapiParams) { + public CompletableFuture<User> lookUpUserById(String userId, RequestContext requestCtx) { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); - headers.addAll(okapiParams.getHeaders()); + headers.addAll(requestCtx.getHeaders()); headers.add(HttpHeaders.ACCEPT, HttpHeaderValues.APPLICATION_JSON); Promise<HttpResponse<JsonObject>> promise = Promise.promise(); @@ -103,7 +104,7 @@ public CompletableFuture<User> lookUpUserById(String userId, OkapiParams okapiPa } private void sendUserRequest(String userId, MultiMap headers, Promise<HttpResponse<JsonObject>> promise) { - String usersPath = String.format(USERS_ENDPOINT_TEMPLATE, userId); + String usersPath = String.format(USERS_BY_ID_ENDPOINT, userId); webClient.getAbs(headers.get(XOkapiHeaders.URL) + usersPath) .putHeaders(headers) .as(BodyCodec.jsonObject()) @@ -133,19 +134,20 @@ private Completable<HttpResponse<JsonObject>> handleUserResponse(Promise<HttpRes }; } - private CompletableFuture<List<User>> lookUpUsersUsingCql(String query, int limit, OkapiParams okapiParams) { - Promise<HttpResponse<JsonObject>> promise = lookUpByCql(USERS_ENDPOINT, query, limit, okapiParams); + private CompletableFuture<List<User>> lookUpUsersUsingCql(String query, int limit, RequestContext requestCtx) { + Promise<HttpResponse<JsonObject>> promise = lookUpByCql(USERS_ENDPOINT, query, limit, requestCtx); return mapVertxFuture(promise.future().map(HttpResponse::body).map(this::mapUserCollection)); } - private CompletableFuture<List<Group>> lookUpGroupsUsingCql(String query, int limit, OkapiParams okapiParams) { - Promise<HttpResponse<JsonObject>> promise = lookUpByCql(GROUPS_ENDPOINT, query, limit, okapiParams); + private CompletableFuture<List<Group>> lookUpGroupsUsingCql(String query, int limit, RequestContext requestCtx) { + Promise<HttpResponse<JsonObject>> promise = lookUpByCql(GROUPS_ENDPOINT, query, limit, requestCtx); return mapVertxFuture(promise.future().map(HttpResponse::body).map(this::mapGroupCollection)); } - private Promise<HttpResponse<JsonObject>> lookUpByCql(String path, String query, int limit, OkapiParams okapiParams) { + private Promise<HttpResponse<JsonObject>> lookUpByCql(String path, String query, int limit, + RequestContext requestCtx) { MultiMap headers = MultiMap.caseInsensitiveMultiMap(); - headers.addAll(okapiParams.getHeaders()); + headers.addAll(requestCtx.getHeaders()); headers.add(HttpHeaders.ACCEPT, HttpHeaderValues.APPLICATION_JSON); Promise<HttpResponse<JsonObject>> promise = Promise.promise(); diff --git a/src/main/java/org/folio/spring/config/ApplicationConfig.java b/src/main/java/org/folio/spring/config/ApplicationConfig.java index 90342fe7c..7fe0cba86 100644 --- a/src/main/java/org/folio/spring/config/ApplicationConfig.java +++ b/src/main/java/org/folio/spring/config/ApplicationConfig.java @@ -33,7 +33,7 @@ import org.folio.db.exc.DatabaseException; import org.folio.db.exc.translation.DBExceptionTranslator; import org.folio.db.exc.translation.DBExceptionTranslatorFactory; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.VendorById; import org.folio.holdingsiq.service.ConfigurationService; @@ -115,13 +115,13 @@ public VertxCache<String, org.folio.holdingsiq.model.Configuration> rmApiConfigu } @Bean - public VertxCache<VendorIdCacheKey, Long> vendorIdCache(Vertx vertx, + public VertxCache<VendorIdCacheKey, Integer> vendorIdCache(Vertx vertx, @Value("${vendor.id.cache.expire}") long expirationTime) { return new VertxCache<>(vertx, expirationTime, "vendorIdCache"); } @Bean - public VertxCache<PackageCacheKey, PackageByIdData> packageCache(Vertx vertx, + public VertxCache<PackageCacheKey, PackageData> packageCache(Vertx vertx, @Value("${package.cache.expire}") long expirationTime) { return new VertxCache<>(vertx, expirationTime, "packageCache"); @@ -312,8 +312,10 @@ public CustomLabelsProperties customLabelsProperties( @Bean public SearchProperties searchProperties(@Value("${kb.ebsco.search-type.titles}") String titlesSearchType, - @Value("${kb.ebsco.search-type.packages}") String packagesSearchType) { - return new SearchProperties(titlesSearchType, packagesSearchType); + @Value("${kb.ebsco.search-type.packages}") String packagesSearchType, + @Value("${kb-ebsco.highlight-tag}") String highlightTag + ) { + return new SearchProperties(titlesSearchType, packagesSearchType, highlightTag); } @Bean diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 62431c109..2973a4d10 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -51,3 +51,4 @@ kb.ebsco.custom.labels.value.length.max=500 # HoldingsIQ search type properties kb.ebsco.search-type.titles=advanced kb.ebsco.search-type.packages=advanced +kb-ebsco.highlight-tag=mark diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 75f9a5451..5a7cafd9b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -48,3 +48,4 @@ kb.ebsco.custom.labels.value.length.max=500 # HoldingsIQ search type properties kb.ebsco.search-type.titles=advanced kb.ebsco.search-type.packages=advanced +kb-ebsco.highlight-tag=mark diff --git a/src/test/java/org/folio/common/LogUtilsTest.java b/src/test/java/org/folio/common/LogUtilsTest.java index 60b891423..77379071d 100644 --- a/src/test/java/org/folio/common/LogUtilsTest.java +++ b/src/test/java/org/folio/common/LogUtilsTest.java @@ -5,28 +5,28 @@ import java.util.Arrays; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class LogUtilsTest { +class LogUtilsTest { private static final List<String> BIG_LIST = Arrays.asList("One", "Two", "Three"); private static final List<String> SMALL_LIST = Arrays.asList("One", "Two"); private static final String MSG = "size of list "; @Test - public void collectionToLogMsg_moreThanThreeItems() { + void collectionToLogMsg_moreThanThreeItems() { var actual = collectionToLogMsg(BIG_LIST); assertThat(actual).isEqualTo(MSG + BIG_LIST.size()); } @Test - public void testCollectionToLogMsg_lessThenThreeItems() { + void collectionToLogMsgLessThenThreeItems() { var actual = collectionToLogMsg(SMALL_LIST); assertThat(actual).isEqualTo(SMALL_LIST.toString()); } @Test - public void testCollectionToLogMsg_nullOrEmptyList() { + void collectionToLogMsgNullOrEmptyList() { var actual = collectionToLogMsg(null); assertThat(actual).isEqualTo(MSG + 0); } diff --git a/src/test/java/org/folio/repository/packages/PackageRepositoryImplTest.java b/src/test/java/org/folio/repository/packages/PackageRepositoryImplTest.java index e3c34de81..3d94de16d 100644 --- a/src/test/java/org/folio/repository/packages/PackageRepositoryImplTest.java +++ b/src/test/java/org/folio/repository/packages/PackageRepositoryImplTest.java @@ -1,49 +1,46 @@ package org.folio.repository.packages; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collections; -import java.util.List; import org.folio.repository.RecordType; import org.folio.rest.model.filter.TagFilter; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class PackageRepositoryImplTest { +class PackageRepositoryImplTest { @Autowired PackageRepository repository; @Test - public void shouldReturnEmptyListWhenIdListIsEmpty() { - List<DbPackage> packages = repository.findByIds(Collections.emptyList(), null, null).join(); - assertThat(packages, empty()); + void shouldReturnEmptyListWhenIdListIsEmpty() { + var packages = repository.findByIds(Collections.emptyList(), null, null).join(); + assertTrue(packages.isEmpty()); } @Test - public void shouldReturnEmptyListWhenTagListIsEmpty() { - TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) + void shouldReturnEmptyListWhenTagListIsEmpty() { + var filter = TagFilter.builder().tags(Collections.emptyList()) .recordType(RecordType.PACKAGE) .count(25).offset(0).build(); - List<DbPackage> packages = repository.findByTagFilter(filter, null, STUB_TENANT).join(); - assertThat(packages, empty()); + var packages = repository.findByTagFilter(filter, null, STUB_TENANT).join(); + assertTrue(packages.isEmpty()); } @Test - public void shouldReturnEmptyListWhenTagListIsEmptyAndProviderIdIsPresent() { - TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) - .recordIdPrefix(STUB_VENDOR_ID).recordType(RecordType.PACKAGE) + void shouldReturnEmptyListWhenTagListIsEmptyAndProviderIdIsPresent() { + var filter = TagFilter.builder().tags(Collections.emptyList()) + .recordIdPrefix("vendor-id").recordType(RecordType.PACKAGE) .count(25).offset(0).build(); - List<DbPackage> packages = repository.findByTagFilter(filter, null, null).join(); - assertThat(packages, empty()); + var packages = repository.findByTagFilter(filter, null, null).join(); + assertTrue(packages.isEmpty()); } } diff --git a/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java b/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java index 2d4c16994..d57396995 100644 --- a/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java +++ b/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java @@ -1,33 +1,31 @@ package org.folio.repository.providers; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collections; -import java.util.List; import org.folio.repository.RecordType; import org.folio.rest.model.filter.TagFilter; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class ProviderRepositoryImplTest { +class ProviderRepositoryImplTest { @Autowired - ProviderRepository repository; + private ProviderRepository repository; @Test - public void shouldReturnEmptyListWhenTagListIsEmpty() { - TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) + void shouldReturnEmptyListWhenTagListIsEmpty() { + var filter = TagFilter.builder().tags(Collections.emptyList()) .recordType(RecordType.PROVIDER) .build(); - List<Long> providerIds = repository.findIdsByTagFilter(filter, null, STUB_TENANT).join(); - assertThat(providerIds, empty()); + var providerIds = repository.findIdsByTagFilter(filter, null, STUB_TENANT).join(); + assertTrue(providerIds.isEmpty()); } } diff --git a/src/test/java/org/folio/repository/resources/ResourcesRepositoryImplTest.java b/src/test/java/org/folio/repository/resources/ResourcesRepositoryImplTest.java index 88c3e3dc1..89a959813 100644 --- a/src/test/java/org/folio/repository/resources/ResourcesRepositoryImplTest.java +++ b/src/test/java/org/folio/repository/resources/ResourcesRepositoryImplTest.java @@ -1,35 +1,31 @@ package org.folio.repository.resources; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collections; -import java.util.List; import org.folio.repository.RecordType; import org.folio.rest.model.filter.TagFilter; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class ResourcesRepositoryImplTest { +class ResourcesRepositoryImplTest { @Autowired - ResourceRepository repository; + private ResourceRepository repository; @Test - public void shouldReturnEmptyListWhenTagListIsEmpty() { - TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) - .recordIdPrefix(STUB_PACKAGE_ID).recordType(RecordType.RESOURCE) + void shouldReturnEmptyListWhenTagListIsEmpty() { + var filter = TagFilter.builder().tags(Collections.emptyList()) + .recordIdPrefix("package-id").recordType(RecordType.RESOURCE) .count(25).offset(0).build(); - List<DbResource> resources = repository.findByTagFilter( - filter, null, STUB_TENANT).join(); - assertThat(resources, empty()); + var resources = repository.findByTagFilter(filter, null, STUB_TENANT).join(); + assertTrue(resources.isEmpty()); } } diff --git a/src/test/java/org/folio/repository/tag/TagRepositoryImplTest.java b/src/test/java/org/folio/repository/tag/TagRepositoryImplTest.java index 1f4e2d160..26f598406 100644 --- a/src/test/java/org/folio/repository/tag/TagRepositoryImplTest.java +++ b/src/test/java/org/folio/repository/tag/TagRepositoryImplTest.java @@ -1,33 +1,30 @@ package org.folio.repository.tag; import static java.util.Collections.emptyList; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; -import static org.junit.Assert.assertEquals; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collections; -import java.util.List; -import java.util.Map; import org.folio.repository.RecordType; import org.folio.rest.model.filter.TagFilter; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class TagRepositoryImplTest { +class TagRepositoryImplTest { @Autowired private TagRepository repository; @Test - public void shouldReturnZeroWhenTagListIsEmptyOnCountRecordsByTags() { - TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) + void shouldReturnZeroWhenTagListIsEmptyOnCountRecordsByTags() { + var filter = TagFilter.builder().tags(Collections.emptyList()) .recordType(RecordType.RESOURCE) .build(); int count = repository.countRecordsByTagFilter(filter, STUB_TENANT).join(); @@ -35,8 +32,8 @@ public void shouldReturnZeroWhenTagListIsEmptyOnCountRecordsByTags() { } @Test - public void shouldReturnZeroWhenTagListIsEmptyOnCountRecordsByTagsAndPrefix() { - TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) + void shouldReturnZeroWhenTagListIsEmptyOnCountRecordsByTagsAndPrefix() { + var filter = TagFilter.builder().tags(Collections.emptyList()) .recordType(RecordType.RESOURCE) .recordIdPrefix("123") .build(); @@ -45,14 +42,14 @@ public void shouldReturnZeroWhenTagListIsEmptyOnCountRecordsByTagsAndPrefix() { } @Test - public void shouldReturnEmptyListWhenIdListIsEmptyOnFindByRecordByIds() { - List<DbTag> tags = repository.findByRecordByIds(STUB_TENANT, emptyList(), RecordType.RESOURCE).join(); - assertThat(tags, empty()); + void shouldReturnEmptyListWhenIdListIsEmptyOnFindByRecordByIds() { + var tags = repository.findByRecordByIds(STUB_TENANT, emptyList(), RecordType.RESOURCE).join(); + assertTrue(tags.isEmpty()); } @Test - public void shouldReturnEmptyMapWhenIdListIsEmptyOnFindByRecordByIds() { - Map<String, List<DbTag>> tags = repository.findPerRecord(STUB_TENANT, emptyList(), RecordType.RESOURCE).join(); - assertThat(tags.keySet(), empty()); + void shouldReturnEmptyMapWhenIdListIsEmptyOnFindByRecordByIds() { + var tags = repository.findPerRecord(STUB_TENANT, emptyList(), RecordType.RESOURCE).join(); + assertTrue(tags.isEmpty()); } } diff --git a/src/test/java/org/folio/repository/titles/TitleRepositoryImplTest.java b/src/test/java/org/folio/repository/titles/TitleRepositoryImplTest.java index 90a4ea983..8a65cd82a 100644 --- a/src/test/java/org/folio/repository/titles/TitleRepositoryImplTest.java +++ b/src/test/java/org/folio/repository/titles/TitleRepositoryImplTest.java @@ -1,39 +1,38 @@ package org.folio.repository.titles; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; -import static org.junit.Assert.assertEquals; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collections; -import java.util.List; import org.folio.repository.RecordType; import org.folio.rest.model.filter.TagFilter; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class TitleRepositoryImplTest { +class TitleRepositoryImplTest { + @Autowired - TitlesRepository repository; + private TitlesRepository repository; @Test - public void shouldReturnZeroWhenTagListIsEmpty() { + void shouldReturnZeroWhenTagListIsEmpty() { int count = repository.countTitlesByResourceTags(Collections.emptyList(), null, STUB_TENANT).join(); assertEquals(0, count); } @Test - public void shouldReturnEmptyListWhenTagListIsEmpty() { - TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) + void shouldReturnEmptyListWhenTagListIsEmpty() { + var filter = TagFilter.builder().tags(Collections.emptyList()) .recordType(RecordType.RESOURCE) .build(); - List<DbTitle> titles = repository.findByTagFilter(filter, null, STUB_TENANT).join(); - assertThat(titles, empty()); + var titles = repository.findByTagFilter(filter, null, STUB_TENANT).join(); + assertTrue(titles.isEmpty()); } } diff --git a/src/test/java/org/folio/rest/converter/accesstypes/AccessTypeCollectionConverterTest.java b/src/test/java/org/folio/rest/converter/accesstypes/AccessTypeCollectionConverterTest.java index 17b680632..ebb7c899f 100644 --- a/src/test/java/org/folio/rest/converter/accesstypes/AccessTypeCollectionConverterTest.java +++ b/src/test/java/org/folio/rest/converter/accesstypes/AccessTypeCollectionConverterTest.java @@ -1,21 +1,18 @@ package org.folio.rest.converter.accesstypes; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.util.List; -import org.folio.rest.jaxrs.model.AccessType; -import org.folio.rest.jaxrs.model.AccessTypeCollection; import org.folio.util.AccessTypesTestUtil; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class AccessTypeCollectionConverterTest { +class AccessTypeCollectionConverterTest { @Test - public void testConvertCollection() { - List<AccessType> accessTypes = AccessTypesTestUtil.testData(); + void convertCollection() { + var accessTypes = AccessTypesTestUtil.testData(); - AccessTypeCollection convertedCollection = new AccessTypeCollectionConverter().convert(accessTypes); + var convertedCollection = new AccessTypeCollectionConverter().convert(accessTypes); assertNotNull(convertedCollection); assertNotNull(convertedCollection.getData()); diff --git a/src/test/java/org/folio/rest/converter/common/attr/EmbargoPeriodConverterTest.java b/src/test/java/org/folio/rest/converter/common/attr/EmbargoPeriodConverterTest.java index 6d0b9440e..1ec23a0a4 100644 --- a/src/test/java/org/folio/rest/converter/common/attr/EmbargoPeriodConverterTest.java +++ b/src/test/java/org/folio/rest/converter/common/attr/EmbargoPeriodConverterTest.java @@ -3,94 +3,79 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.oneOf; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Arrays; +import java.util.stream.Stream; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomUtils; -import org.folio.rest.jaxrs.model.EmbargoPeriod; +import org.folio.holdingsiq.model.EmbargoPeriod; import org.folio.rest.jaxrs.model.EmbargoPeriod.EmbargoUnit; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.FromDataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Theories.class) -public class EmbargoPeriodConverterTest { +class EmbargoPeriodConverterTest { private static final int MIN_VALUE = 1; private static final int MAX_VALUE = 100; - private EmbargoPeriodConverter converter; + private final EmbargoPeriodConverter converter = new EmbargoPeriodConverter(); - @DataPoints("valid-periods") - public static org.folio.holdingsiq.model.EmbargoPeriod[] validPeriods() { - return Arrays.stream(EmbargoUnit.values()) - .map(unit -> createPeriod(unit.value(), randomValue())) - .toArray(org.folio.holdingsiq.model.EmbargoPeriod[]::new); + @ParameterizedTest + @MethodSource("validPeriods") + void testEmbargoPeriodWithValidUnitConverted(EmbargoPeriod period) { + testEmbargoPeriod(period); } - @DataPoints("mixed-case-units") - public static org.folio.holdingsiq.model.EmbargoPeriod[] periodsWithMixedCaseUnits() { - return Arrays.stream(EmbargoUnit.values()) - .map(unit -> createPeriod(mixCase(unit.value()), randomValue())) - .toArray(org.folio.holdingsiq.model.EmbargoPeriod[]::new); + @ParameterizedTest + @MethodSource("periodsWithMixedCaseUnits") + void testCharacterCaseOfUnitIgnored(EmbargoPeriod period) { + testEmbargoPeriod(period); } - @DataPoints("invalid-units") - public static org.folio.holdingsiq.model.EmbargoPeriod[] periodsWithInvalidUnits() { - return ArrayUtils.toArray( - createPeriod(RandomStringUtils.insecure().nextAlphanumeric(10), randomValue()), // randomly generated unit name + - createPeriod(null, randomValue()) // unit == null - ); - } + @ParameterizedTest + @MethodSource("periodsWithInvalidUnits") + void testInvalidEmbargoUnitConvertedToNull(EmbargoPeriod period) { + var result = converter.convert(period); - @Before - public void setUp() { - converter = new EmbargoPeriodConverter(); + assertNotNull(result); + assertNull(result.getEmbargoUnit()); + assertThat(result.getEmbargoValue(), allOf(greaterThanOrEqualTo(MIN_VALUE), lessThanOrEqualTo(MAX_VALUE))); } @Test - public void testNullEmbargoPeriodConvertedToNull() { - EmbargoPeriod result = converter.convert(null); + void nullEmbargoPeriodConvertedToNull() { + var result = converter.convert(null); assertNull(result); } - @Theory - public void testEmbargoPeriodWithValidUnitConverted( - @FromDataPoints("valid-periods") org.folio.holdingsiq.model.EmbargoPeriod period) { - testEmbargoPeriod(period); + private static Stream<EmbargoPeriod> validPeriods() { + return Arrays.stream(EmbargoUnit.values()) + .map(unit -> createPeriod(unit.value(), randomValue())); } - @Theory - public void testCharacterCaseOfUnitIgnored( - @FromDataPoints("mixed-case-units") org.folio.holdingsiq.model.EmbargoPeriod period) { - testEmbargoPeriod(period); + private static Stream<EmbargoPeriod> periodsWithMixedCaseUnits() { + return Arrays.stream(EmbargoUnit.values()) + .map(unit -> createPeriod(mixCase(unit.value()), randomValue())); } - @Theory - public void testInvalidEmbargoUnitConvertedToNull( - @FromDataPoints("invalid-units") org.folio.holdingsiq.model.EmbargoPeriod period) { - EmbargoPeriod result = converter.convert(period); - - assertNotNull(result); - assertNull(result.getEmbargoUnit()); - assertThat(result.getEmbargoValue(), allOf(greaterThanOrEqualTo(MIN_VALUE), lessThanOrEqualTo(MAX_VALUE))); + private static Stream<EmbargoPeriod> periodsWithInvalidUnits() { + return Arrays.stream(ArrayUtils.toArray( + createPeriod(RandomStringUtils.insecure().nextAlphanumeric(10), randomValue()), + createPeriod(null, randomValue()) + )); } - private void testEmbargoPeriod(org.folio.holdingsiq.model.EmbargoPeriod period) { - EmbargoPeriod result = converter.convert(period); + private void testEmbargoPeriod(EmbargoPeriod period) { + var result = converter.convert(period); assertNotNull(result); - assertThat(result.getEmbargoUnit(), is(oneOf(EmbargoUnit.values()))); + assertThat(result.getEmbargoUnit(), oneOf(EmbargoUnit.values())); assertThat(result.getEmbargoValue(), allOf(greaterThanOrEqualTo(MIN_VALUE), lessThanOrEqualTo(MAX_VALUE))); } @@ -110,8 +95,8 @@ private static int randomValue() { return RandomUtils.insecure().randomInt(MIN_VALUE, MAX_VALUE); } - private static org.folio.holdingsiq.model.EmbargoPeriod createPeriod(String unit, int value) { - return org.folio.holdingsiq.model.EmbargoPeriod.builder() + private static EmbargoPeriod createPeriod(String unit, int value) { + return EmbargoPeriod.builder() .embargoUnit(unit) .embargoValue(value).build(); } diff --git a/src/test/java/org/folio/rest/converter/export/PackageTitleCostPerUseConverterTest.java b/src/test/java/org/folio/rest/converter/export/PackageTitleCostPerUseConverterTest.java index b166378b4..b1303b999 100644 --- a/src/test/java/org/folio/rest/converter/export/PackageTitleCostPerUseConverterTest.java +++ b/src/test/java/org/folio/rest/converter/export/PackageTitleCostPerUseConverterTest.java @@ -1,6 +1,6 @@ package org.folio.rest.converter.export; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.math.RoundingMode; import java.text.DecimalFormat; @@ -14,21 +14,21 @@ import org.folio.rest.jaxrs.model.ResourceCostAnalysisAttributes; import org.folio.rest.jaxrs.model.ResourceCostPerUseCollectionItem; import org.folio.service.uc.export.TitleExportModel; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class PackageTitleCostPerUseConverterTest { +class PackageTitleCostPerUseConverterTest { private PackageTitleCostPerUseConverter converter; private NumberFormat currencyFormatter; - @Before - public void setUp() { + @BeforeEach + void setUp() { converter = new PackageTitleCostPerUseConverter(); } @Test - public void shouldRoundPercentToLessThanOne() { + void shouldRoundPercentToLessThanOne() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -46,7 +46,7 @@ public void shouldRoundPercentToLessThanOne() { } @Test - public void shouldRoundPercentToLower() { + void shouldRoundPercentToLower() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -64,7 +64,7 @@ public void shouldRoundPercentToLower() { } @Test - public void shouldRoundPercentToHigher() { + void shouldRoundPercentToHigher() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -82,7 +82,7 @@ public void shouldRoundPercentToHigher() { } @Test - public void shouldRoundDownCosts() { + void shouldRoundDownCosts() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -101,7 +101,7 @@ public void shouldRoundDownCosts() { } @Test - public void shouldRoundUpCosts() { + void shouldRoundUpCosts() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -120,7 +120,7 @@ public void shouldRoundUpCosts() { } @Test - public void shouldFormatCostsToUsFormat() { + void shouldFormatCostsToUsFormat() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -139,7 +139,7 @@ public void shouldFormatCostsToUsFormat() { } @Test - public void shouldFormatCostsToGbFormat() { + void shouldFormatCostsToGbFormat() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -158,7 +158,7 @@ public void shouldFormatCostsToGbFormat() { } @Test - public void shouldFormatCostsToFrFormat() { + void shouldFormatCostsToFrFormat() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -177,7 +177,7 @@ public void shouldFormatCostsToFrFormat() { } @Test - public void shouldFormatCostsToUkFormat() { + void shouldFormatCostsToUkFormat() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -196,7 +196,7 @@ public void shouldFormatCostsToUkFormat() { } @Test - public void shouldFormatCostsToKoreanFormat() { + void shouldFormatCostsToKoreanFormat() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() @@ -215,7 +215,7 @@ public void shouldFormatCostsToKoreanFormat() { } @Test - public void shouldFormatCostsToJordanFormat() { + void shouldFormatCostsToJordanFormat() { ResourceCostPerUseCollectionItem item = new ResourceCostPerUseCollectionItem() .withAttributes( new ResourceCostAnalysisAttributes() diff --git a/src/test/java/org/folio/rest/converter/holdings/HoldingsCollectionItemConverterTest.java b/src/test/java/org/folio/rest/converter/holdings/HoldingsCollectionItemConverterTest.java index d0fd08947..68ecd7e63 100644 --- a/src/test/java/org/folio/rest/converter/holdings/HoldingsCollectionItemConverterTest.java +++ b/src/test/java/org/folio/rest/converter/holdings/HoldingsCollectionItemConverterTest.java @@ -1,38 +1,30 @@ package org.folio.rest.converter.holdings; -import static org.folio.util.HoldingsTestUtil.getStubHolding; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.io.IOException; -import java.net.URISyntaxException; import org.folio.repository.holdings.DbHoldingInfo; import org.folio.rest.jaxrs.model.PublicationType; -import org.folio.rest.jaxrs.model.ResourceCollectionItem; -import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.junit.jupiter.api.Test; -@RunWith(SpringRunner.class) -@ContextConfiguration(classes = TestConfig.class) -public class HoldingsCollectionItemConverterTest { +class HoldingsCollectionItemConverterTest { - @Autowired - private HoldingCollectionItemConverter holdingCollectionItemConverter; + private final HoldingCollectionItemConverter holdingCollectionItemConverter = new HoldingCollectionItemConverter(); @Test - public void shouldConvertHoldingToResource() throws IOException, URISyntaxException { - DbHoldingInfo holding = getStubHolding(); - final ResourceCollectionItem resourceCollectionItem = holdingCollectionItemConverter.convert(holding); - assertThat(resourceCollectionItem, notNullValue()); - assertThat(resourceCollectionItem.getId(), equalTo("123356-3157070-19412030")); - assertThat(resourceCollectionItem.getAttributes().getName(), equalTo("Test Title")); - assertThat(resourceCollectionItem.getAttributes().getTitleId(), equalTo(19412030)); - assertThat(resourceCollectionItem.getAttributes().getPublisherName(), equalTo("Test one Press")); - assertThat(resourceCollectionItem.getAttributes().getPublicationType(), equalTo(PublicationType.BOOK)); + void shouldConvertHoldingToResource() { + var holding = getStubHolding(); + var resourceCollectionItem = holdingCollectionItemConverter.convert(holding); + assertNotNull(resourceCollectionItem); + assertEquals("123356-3157070-19412030", resourceCollectionItem.getId()); + assertEquals("Test Title", resourceCollectionItem.getAttributes().getName()); + assertEquals(19412030, resourceCollectionItem.getAttributes().getTitleId()); + assertEquals("Test one Press", resourceCollectionItem.getAttributes().getPublisherName()); + assertEquals(PublicationType.BOOK, resourceCollectionItem.getAttributes().getPublicationType()); + } + + private static DbHoldingInfo getStubHolding() { + return readJsonFile("responses/kb-ebsco/holdings/custom-holding.json", DbHoldingInfo.class); } } diff --git a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredCollectionConverterTest.java b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredCollectionConverterTest.java index 7ba339cf8..3394c2904 100644 --- a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredCollectionConverterTest.java +++ b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredCollectionConverterTest.java @@ -1,31 +1,27 @@ package org.folio.rest.converter.kbcredentials; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_KEY; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_CUSTOMER_ID; +import static org.folio.util.KbCredentialsTestUtil.API_KEY; +import static org.folio.util.KbCredentialsTestUtil.API_URL; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.CUSTOMER_ID; import static org.folio.util.KbCredentialsTestUtil.getCredentialsCollection; import static org.folio.util.KbCredentialsTestUtil.getCredentialsCollectionNoUrl; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.util.Collection; -import org.folio.repository.kbcredentials.DbKbCredentials; import org.folio.rest.jaxrs.model.KbCredentials; -import org.folio.rest.jaxrs.model.KbCredentialsCollection; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class KbCredentialsNotSecuredCollectionConverterTest { +class KbCredentialsNotSecuredCollectionConverterTest { @Autowired @Qualifier("nonSecuredCredentialsCollection") @@ -34,30 +30,30 @@ public class KbCredentialsNotSecuredCollectionConverterTest { private String defaultUrl; @Test - public void shouldConvertKbCredentialsCollectionWithDefaultUrl() { - Collection<DbKbCredentials> credentialsCollection = getCredentialsCollectionNoUrl(); - final KbCredentialsCollection kbCredentials = nonSecuredConverter.convert(credentialsCollection); - assertThat(kbCredentials, notNullValue()); - assertThat(kbCredentials.getMeta().getTotalResults(), equalTo(1)); + void shouldConvertKbCredentialsCollectionWithDefaultUrl() { + var credentialsCollection = getCredentialsCollectionNoUrl(); + var kbCredentials = nonSecuredConverter.convert(credentialsCollection); + assertNotNull(kbCredentials); + assertEquals(1, kbCredentials.getMeta().getTotalResults()); var credentials = kbCredentials.getData().getFirst(); - assertThat(credentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(credentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(credentials.getAttributes().getApiKey(), equalTo(STUB_API_KEY)); - assertThat(credentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(credentials.getAttributes().getUrl(), equalTo(defaultUrl)); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, credentials.getType()); + assertEquals(CREDENTIALS_NAME, credentials.getAttributes().getName()); + assertEquals(API_KEY, credentials.getAttributes().getApiKey()); + assertEquals(CUSTOMER_ID, credentials.getAttributes().getCustomerId()); + assertEquals(credentials.getAttributes().getUrl(), defaultUrl); } @Test - public void shouldConvertKbCredentialsCollection() { - Collection<DbKbCredentials> credentialsCollection = getCredentialsCollection(); - final KbCredentialsCollection kbCredentials = nonSecuredConverter.convert(credentialsCollection); - assertThat(kbCredentials, notNullValue()); - assertThat(kbCredentials.getMeta().getTotalResults(), equalTo(1)); + void shouldConvertKbCredentialsCollection() { + var credentialsCollection = getCredentialsCollection(); + var kbCredentials = nonSecuredConverter.convert(credentialsCollection); + assertNotNull(kbCredentials); + assertEquals(1, kbCredentials.getMeta().getTotalResults()); var credentials = kbCredentials.getData().getFirst(); - assertThat(credentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(credentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(credentials.getAttributes().getApiKey(), equalTo(STUB_API_KEY)); - assertThat(credentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(credentials.getAttributes().getUrl(), equalTo(STUB_API_URL)); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, credentials.getType()); + assertEquals(CREDENTIALS_NAME, credentials.getAttributes().getName()); + assertEquals(API_KEY, credentials.getAttributes().getApiKey()); + assertEquals(CUSTOMER_ID, credentials.getAttributes().getCustomerId()); + assertEquals(API_URL, credentials.getAttributes().getUrl()); } } diff --git a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredConverterTest.java b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredConverterTest.java index b848cc92f..cc296cc77 100644 --- a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredConverterTest.java +++ b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsNotSecuredConverterTest.java @@ -1,28 +1,26 @@ package org.folio.rest.converter.kbcredentials; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_KEY; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_CUSTOMER_ID; +import static org.folio.util.KbCredentialsTestUtil.API_KEY; +import static org.folio.util.KbCredentialsTestUtil.API_URL; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.CUSTOMER_ID; import static org.folio.util.KbCredentialsTestUtil.getCredentials; import static org.folio.util.KbCredentialsTestUtil.getCredentialsNoUrl; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.folio.repository.kbcredentials.DbKbCredentials; import org.folio.rest.jaxrs.model.KbCredentials; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class KbCredentialsNotSecuredConverterTest { +class KbCredentialsNotSecuredConverterTest { @Autowired @Qualifier("nonSecured") @@ -31,24 +29,24 @@ public class KbCredentialsNotSecuredConverterTest { private String defaultUrl; @Test - public void shouldConvertKbCredentialsWithDefaultUrl() { - DbKbCredentials holding = getCredentialsNoUrl(); - final KbCredentials kbCredentials = notSecuredConverter.convert(holding); - assertThat(kbCredentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(kbCredentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(kbCredentials.getAttributes().getApiKey(), equalTo(STUB_API_KEY)); - assertThat(kbCredentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(kbCredentials.getAttributes().getUrl(), equalTo(defaultUrl)); + void shouldConvertKbCredentialsWithDefaultUrl() { + var dbKbCredentials = getCredentialsNoUrl(); + var kbCredentials = notSecuredConverter.convert(dbKbCredentials); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, kbCredentials.getType()); + assertEquals(CREDENTIALS_NAME, kbCredentials.getAttributes().getName()); + assertEquals(API_KEY, kbCredentials.getAttributes().getApiKey()); + assertEquals(CUSTOMER_ID, kbCredentials.getAttributes().getCustomerId()); + assertEquals(kbCredentials.getAttributes().getUrl(), defaultUrl); } @Test - public void shouldConvertKbCredentials() { - DbKbCredentials holding = getCredentials(); - final KbCredentials kbCredentials = notSecuredConverter.convert(holding); - assertThat(kbCredentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(kbCredentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(kbCredentials.getAttributes().getApiKey(), equalTo(STUB_API_KEY)); - assertThat(kbCredentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(kbCredentials.getAttributes().getUrl(), equalTo(STUB_API_URL)); + void shouldConvertKbCredentials() { + var dbKbCredentials = getCredentials(); + var kbCredentials = notSecuredConverter.convert(dbKbCredentials); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, kbCredentials.getType()); + assertEquals(CREDENTIALS_NAME, kbCredentials.getAttributes().getName()); + assertEquals(API_KEY, kbCredentials.getAttributes().getApiKey()); + assertEquals(CUSTOMER_ID, kbCredentials.getAttributes().getCustomerId()); + assertEquals(API_URL, kbCredentials.getAttributes().getUrl()); } } diff --git a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredCollectionConverterTest.java b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredCollectionConverterTest.java index 3a2f68159..f1ce2528e 100644 --- a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredCollectionConverterTest.java +++ b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredCollectionConverterTest.java @@ -1,30 +1,26 @@ package org.folio.rest.converter.kbcredentials; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_CUSTOMER_ID; +import static org.folio.util.KbCredentialsTestUtil.API_URL; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.CUSTOMER_ID; import static org.folio.util.KbCredentialsTestUtil.getCredentialsCollection; import static org.folio.util.KbCredentialsTestUtil.getCredentialsCollectionNoUrl; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.Collection; -import org.folio.repository.kbcredentials.DbKbCredentials; import org.folio.rest.jaxrs.model.KbCredentials; -import org.folio.rest.jaxrs.model.KbCredentialsCollection; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class KbCredentialsSecuredCollectionConverterTest { +class KbCredentialsSecuredCollectionConverterTest { @Autowired private KbCredentialsCollectionConverter.SecuredKbCredentialsCollectionConverter securedConverter; @@ -32,30 +28,30 @@ public class KbCredentialsSecuredCollectionConverterTest { private String defaultUrl; @Test - public void shouldConvertKbCredentialsCollectionWithDefaultUrl() { - Collection<DbKbCredentials> credentialsCollection = getCredentialsCollectionNoUrl(); - final KbCredentialsCollection kbCredentials = securedConverter.convert(credentialsCollection); - assertThat(kbCredentials, notNullValue()); - assertThat(kbCredentials.getMeta().getTotalResults(), equalTo(1)); + void shouldConvertKbCredentialsCollectionWithDefaultUrl() { + var credentialsCollection = getCredentialsCollectionNoUrl(); + var kbCredentials = securedConverter.convert(credentialsCollection); + assertNotNull(kbCredentials); + assertEquals(1, kbCredentials.getMeta().getTotalResults()); var credentials = kbCredentials.getData().getFirst(); - assertThat(credentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(credentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(credentials.getAttributes().getApiKey(), containsString("*")); - assertThat(credentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(credentials.getAttributes().getUrl(), equalTo(defaultUrl)); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, credentials.getType()); + assertEquals(CREDENTIALS_NAME, credentials.getAttributes().getName()); + assertTrue(credentials.getAttributes().getApiKey().contains("*")); + assertEquals(CUSTOMER_ID, credentials.getAttributes().getCustomerId()); + assertEquals(credentials.getAttributes().getUrl(), defaultUrl); } @Test - public void shouldConvertKbCredentialsCollection() { - Collection<DbKbCredentials> credentialsCollection = getCredentialsCollection(); - final KbCredentialsCollection kbCredentials = securedConverter.convert(credentialsCollection); - assertThat(kbCredentials, notNullValue()); - assertThat(kbCredentials.getMeta().getTotalResults(), equalTo(1)); + void shouldConvertKbCredentialsCollection() { + var credentialsCollection = getCredentialsCollection(); + var kbCredentials = securedConverter.convert(credentialsCollection); + assertNotNull(kbCredentials); + assertEquals(1, kbCredentials.getMeta().getTotalResults()); var credentials = kbCredentials.getData().getFirst(); - assertThat(credentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(credentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(credentials.getAttributes().getApiKey(), containsString("*")); - assertThat(credentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(credentials.getAttributes().getUrl(), equalTo(STUB_API_URL)); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, credentials.getType()); + assertEquals(CREDENTIALS_NAME, credentials.getAttributes().getName()); + assertTrue(credentials.getAttributes().getApiKey().contains("*")); + assertEquals(CUSTOMER_ID, credentials.getAttributes().getCustomerId()); + assertEquals(API_URL, credentials.getAttributes().getUrl()); } } diff --git a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredConverterTest.java b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredConverterTest.java index 8170c9df6..e71b6b9ee 100644 --- a/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredConverterTest.java +++ b/src/test/java/org/folio/rest/converter/kbcredentials/KbCredentialsSecuredConverterTest.java @@ -1,27 +1,25 @@ package org.folio.rest.converter.kbcredentials; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_CUSTOMER_ID; +import static org.folio.util.KbCredentialsTestUtil.API_URL; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.CUSTOMER_ID; import static org.folio.util.KbCredentialsTestUtil.getCredentials; import static org.folio.util.KbCredentialsTestUtil.getCredentialsNoUrl; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.folio.repository.kbcredentials.DbKbCredentials; import org.folio.rest.jaxrs.model.KbCredentials; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class KbCredentialsSecuredConverterTest { +class KbCredentialsSecuredConverterTest { @Autowired private KbCredentialsConverter.KbCredentialsFromDbSecuredConverter securedConverter; @@ -29,24 +27,24 @@ public class KbCredentialsSecuredConverterTest { private String defaultUrl; @Test - public void shouldConvertKbCredentialsWithDefaultUrl() { - DbKbCredentials holding = getCredentialsNoUrl(); - final KbCredentials kbCredentials = securedConverter.convert(holding); - assertThat(kbCredentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(kbCredentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(kbCredentials.getAttributes().getApiKey(), containsString("*")); - assertThat(kbCredentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(kbCredentials.getAttributes().getUrl(), equalTo(defaultUrl)); + void shouldConvertKbCredentialsWithDefaultUrl() { + var dbKbCredentials = getCredentialsNoUrl(); + var kbCredentials = securedConverter.convert(dbKbCredentials); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, kbCredentials.getType()); + assertEquals(CREDENTIALS_NAME, kbCredentials.getAttributes().getName()); + assertTrue(kbCredentials.getAttributes().getApiKey().contains("*")); + assertEquals(CUSTOMER_ID, kbCredentials.getAttributes().getCustomerId()); + assertEquals(kbCredentials.getAttributes().getUrl(), defaultUrl); } @Test - public void shouldConvertKbCredentials() { - DbKbCredentials holding = getCredentials(); - final KbCredentials kbCredentials = securedConverter.convert(holding); - assertThat(kbCredentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(kbCredentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(kbCredentials.getAttributes().getApiKey(), containsString("*")); - assertThat(kbCredentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(kbCredentials.getAttributes().getUrl(), equalTo(STUB_API_URL)); + void shouldConvertKbCredentials() { + var dbKbCredentials = getCredentials(); + var kbCredentials = securedConverter.convert(dbKbCredentials); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, kbCredentials.getType()); + assertEquals(CREDENTIALS_NAME, kbCredentials.getAttributes().getName()); + assertTrue(kbCredentials.getAttributes().getApiKey().contains("*")); + assertEquals(CUSTOMER_ID, kbCredentials.getAttributes().getCustomerId()); + assertEquals(API_URL, kbCredentials.getAttributes().getUrl()); } } diff --git a/src/test/java/org/folio/rest/converter/labels/CustomLabelsCollectionConverterTest.java b/src/test/java/org/folio/rest/converter/labels/CustomLabelsCollectionConverterTest.java index b18bd9f54..97ac9a0d3 100644 --- a/src/test/java/org/folio/rest/converter/labels/CustomLabelsCollectionConverterTest.java +++ b/src/test/java/org/folio/rest/converter/labels/CustomLabelsCollectionConverterTest.java @@ -1,19 +1,17 @@ package org.folio.rest.converter.labels; -import static org.folio.test.util.TestUtil.readJsonFile; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.List; import org.folio.holdingsiq.model.RootProxyCustomLabels; import org.folio.rest.jaxrs.model.CustomLabel; import org.folio.rest.jaxrs.model.CustomLabelsCollection; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.core.convert.converter.Converter; -public class CustomLabelsCollectionConverterTest { +class CustomLabelsCollectionConverterTest { private final Converter<RootProxyCustomLabels, CustomLabelsCollection> fromRmApiConverter = new CustomLabelsCollectionConverter.FromRmApi(new CustomLabelsConverter.FromRmApi()); @@ -22,10 +20,10 @@ public class CustomLabelsCollectionConverterTest { new CustomLabelsCollectionConverter.FromLabelsList(); @Test - public void shouldConvertFromRmApiToCustomLabelsCollection() throws URISyntaxException, IOException { - RootProxyCustomLabels rootProxy = readJsonFile("responses/rmapi/proxiescustomlabels/get-success-response.json", + void shouldConvertFromRmApiToCustomLabelsCollection() { + var rootProxy = readJsonFile("responses/rmapi/proxiescustomlabels/get-success-response.json", RootProxyCustomLabels.class); - CustomLabelsCollection actual = fromRmApiConverter.convert(rootProxy); + var actual = fromRmApiConverter.convert(rootProxy); assertNotNull(actual); assertEquals((Integer) 5, actual.getMeta().getTotalResults()); @@ -33,11 +31,11 @@ public void shouldConvertFromRmApiToCustomLabelsCollection() throws URISyntaxExc } @Test - public void shouldConvertFromListToCustomLabelsCollection() throws URISyntaxException, IOException { - List<CustomLabel> rootProxy = readJsonFile("responses/kb-ebsco/custom-labels/get-custom-labels-list.json", + void shouldConvertFromListToCustomLabelsCollection() { + var customLabels = readJsonFile("responses/kb-ebsco/custom-labels/get-custom-labels-list.json", CustomLabelsCollection.class).getData(); - CustomLabelsCollection actual = fromLabelsListConverter.convert(rootProxy); + var actual = fromLabelsListConverter.convert(customLabels); assertNotNull(actual); assertEquals((Integer) 5, actual.getMeta().getTotalResults()); diff --git a/src/test/java/org/folio/rest/converter/labels/CustomLabelsItemCollectionTest.java b/src/test/java/org/folio/rest/converter/labels/CustomLabelsItemCollectionTest.java index 6c5a02a91..332b43eee 100644 --- a/src/test/java/org/folio/rest/converter/labels/CustomLabelsItemCollectionTest.java +++ b/src/test/java/org/folio/rest/converter/labels/CustomLabelsItemCollectionTest.java @@ -1,28 +1,25 @@ package org.folio.rest.converter.labels; -import static org.folio.test.util.TestUtil.readJsonFile; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.io.IOException; -import java.net.URISyntaxException; import org.folio.holdingsiq.model.RootProxyCustomLabels; import org.folio.rest.jaxrs.model.CustomLabel; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.core.convert.converter.Converter; -public class CustomLabelsItemCollectionTest { +class CustomLabelsItemCollectionTest { private final Converter<org.folio.holdingsiq.model.CustomLabel, CustomLabel> itemConverter = new CustomLabelsConverter.FromRmApi(); @Test - public void shouldConvertToCustomLabelOnly() throws URISyntaxException, IOException { - org.folio.holdingsiq.model.CustomLabel rmCustomLabel = - readJsonFile("responses/rmapi/proxiescustomlabels/get-success-response.json", - RootProxyCustomLabels.class).getLabelList().getFirst(); + void shouldConvertToCustomLabelOnly() { + var rmCustomLabel = readJsonFile("responses/rmapi/proxiescustomlabels/get-success-response.json", + RootProxyCustomLabels.class).getLabelList().getFirst(); - CustomLabel actual = itemConverter.convert(rmCustomLabel); + var actual = itemConverter.convert(rmCustomLabel); assertNotNull(actual); assertEquals((Integer) 1, actual.getAttributes().getId()); diff --git a/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java b/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java index 9f3dcbb8d..aeedc16f8 100644 --- a/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java +++ b/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java @@ -1,48 +1,50 @@ package org.folio.rest.converter.packages; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.folio.util.PackagesTestUtil.getPackagePutRequest; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.folio.holdingsiq.model.PackagePut; -import org.folio.rest.impl.PackagesTestData; +import java.util.List; import org.folio.rest.jaxrs.model.ContentType; import org.folio.rest.jaxrs.model.Coverage; import org.folio.rest.jaxrs.model.PackagePutDataAttributes; -import org.folio.rest.jaxrs.model.VisibilityData; +import org.folio.rest.jaxrs.model.PackageVisibility; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class PackageRequestConverterTest { +class PackageRequestConverterTest { @Autowired private PackageRequestConverter packagesConverter; @Test - public void shouldCreateRequestToSelectPackage() { - PackagePut packagePut = packagesConverter.convertToRmApiPackagePutRequest(PackagesTestData.getPackagePutRequest( + void shouldCreateRequestToSelectPackage() { + var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true))); assertTrue(packagePut.getIsSelected()); } @Test - public void shouldCreateRequestToHidePackage() { - PackagePut packagePut = packagesConverter.convertToRmApiPackagePutRequest(PackagesTestData.getPackagePutRequest( + void shouldCreateRequestToHidePackage() { + var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) - .withVisibilityData(new VisibilityData() - .withIsHidden(true)))); - assertTrue(packagePut.getIsHidden()); + .withVisibility(List.of(new PackageVisibility() + .withHidden(true) + .withCategory(PackageVisibility.Category.PF))) + )); + assertTrue(packagePut.getVisibilityDetails().getFirst().hidden()); } @Test - public void shouldCreateRequestToAllowKbAddTitlesToPackage() { - PackagePut packagePut = packagesConverter.convertToRmApiPackagePutRequest(PackagesTestData.getPackagePutRequest( + void shouldCreateRequestToAllowKbAddTitlesToPackage() { + var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) .withAllowKbToAddTitles(true))); @@ -50,8 +52,8 @@ public void shouldCreateRequestToAllowKbAddTitlesToPackage() { } @Test - public void shouldCreateRequestToAddCustomCoverage() { - PackagePut packagePut = packagesConverter.convertToRmApiPackagePutRequest(PackagesTestData.getPackagePutRequest( + void shouldCreateRequestToAddCustomCoverage() { + var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) .withCustomCoverage(new Coverage() @@ -62,55 +64,53 @@ public void shouldCreateRequestToAddCustomCoverage() { } @Test - public void shouldCreateRequestToChangeCustomPackageName() { - PackagePut packagePut = - packagesConverter.convertToRmApiCustomPackagePutRequest(PackagesTestData.getPackagePutRequest( - new PackagePutDataAttributes() - .withName("new package name"))); + void shouldCreateRequestToChangeCustomPackageName() { + var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest( + new PackagePutDataAttributes() + .withName("new package name"))); assertEquals("new package name", packagePut.getPackageName()); } @Test - public void shouldCreateRequestToChangeCustomPackageCoverageDates() { - PackagePut packagePut = - packagesConverter.convertToRmApiCustomPackagePutRequest(PackagesTestData.getPackagePutRequest( - new PackagePutDataAttributes() - .withCustomCoverage(new Coverage() - .withBeginCoverage("2003-01-01") - .withEndCoverage("2004-01-01")))); + void shouldCreateRequestToChangeCustomPackageCoverageDates() { + var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest( + new PackagePutDataAttributes() + .withCustomCoverage(new Coverage() + .withBeginCoverage("2003-01-01") + .withEndCoverage("2004-01-01")))); assertEquals("2003-01-01", packagePut.getCustomCoverage().getBeginCoverage()); assertEquals("2004-01-01", packagePut.getCustomCoverage().getEndCoverage()); } @Test - public void shouldCreateRequestToChangeCustomPackageCoverageDatesToEmpty() { - PackagePut packagePut = - packagesConverter.convertToRmApiCustomPackagePutRequest(PackagesTestData.getPackagePutRequest( - new PackagePutDataAttributes() - .withCustomCoverage(new Coverage() - .withBeginCoverage("") - .withEndCoverage("")))); + void shouldCreateRequestToChangeCustomPackageCoverageDatesToEmpty() { + var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest( + new PackagePutDataAttributes() + .withCustomCoverage(new Coverage() + .withBeginCoverage("") + .withEndCoverage("")))); assertEquals("", packagePut.getCustomCoverage().getBeginCoverage()); assertEquals("", packagePut.getCustomCoverage().getEndCoverage()); } @Test - public void shouldCreateRequestToChangeCustomPackageContentType() { - PackagePut packagePut = - packagesConverter.convertToRmApiCustomPackagePutRequest(PackagesTestData.getPackagePutRequest( - new PackagePutDataAttributes() - .withContentType(ContentType.STREAMING_MEDIA))); - Integer aggregatedFullTextContentTypeCode = 8; + void shouldCreateRequestToChangeCustomPackageContentType() { + var packagePut = packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest( + new PackagePutDataAttributes() + .withContentType(ContentType.STREAMING_MEDIA))); + var aggregatedFullTextContentTypeCode = 8; assertEquals(aggregatedFullTextContentTypeCode, packagePut.getContentType()); } @Test - public void shouldCreateRequestToChangeCustomPackageVisibility() { - PackagePut packagePut = - packagesConverter.convertToRmApiCustomPackagePutRequest(PackagesTestData.getPackagePutRequest( + void shouldCreateRequestToChangeCustomPackageVisibility() { + var packagePut = + packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest( new PackagePutDataAttributes() - .withVisibilityData(new VisibilityData() - .withIsHidden(true)))); - assertTrue(packagePut.getIsHidden()); + .withVisibility(List.of(new PackageVisibility() + .withHidden(true) + .withCategory(PackageVisibility.Category.PF))) + )); + assertTrue(packagePut.getVisibilityDetails().getFirst().hidden()); } } diff --git a/src/test/java/org/folio/rest/converter/packages/PackageResponseConverterTest.java b/src/test/java/org/folio/rest/converter/packages/PackageResponseConverterTest.java index bf96c4e20..2aa2fbd20 100644 --- a/src/test/java/org/folio/rest/converter/packages/PackageResponseConverterTest.java +++ b/src/test/java/org/folio/rest/converter/packages/PackageResponseConverterTest.java @@ -1,49 +1,41 @@ package org.folio.rest.converter.packages; -import static org.folio.test.util.TestUtil.getFile; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.List; +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import org.folio.holdingsiq.model.Title; -import org.folio.rest.jaxrs.model.Coverage; import org.folio.rest.jaxrs.model.Resource; import org.folio.rmapi.result.ResourceResult; import org.folio.spring.config.TestConfig; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.ConversionService; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = TestConfig.class) -public class PackageResponseConverterTest { +class PackageResponseConverterTest { @Autowired private ConversionService conversionService; @Test - public void shouldReturnCustomCoverageInDescendingOrder() throws URISyntaxException, IOException { - - ObjectMapper mapper = new ObjectMapper(); - - Title title = - mapper.readValue(getFile("responses/rmapi/titles/get-custom-title-with-coverage-dates-asc.json"), Title.class); + void shouldReturnCustomCoverageInDescendingOrder() { + var title = readJsonFile("responses/rmapi/titles/get-custom-title-with-coverage-dates-asc.json", Title.class); - final ResourceResult resourceResult = new ResourceResult(title, null, null, false); - final Resource resource = conversionService.convert(resourceResult, Resource.class); + var resourceResult = new ResourceResult(title, null, null, false); + var resource = conversionService.convert(resourceResult, Resource.class); + assertNotNull(resource); - final List<Coverage> customCoverages = resource.getData().getAttributes().getCustomCoverages(); - assertThat(customCoverages.size(), equalTo(2)); - assertThat(customCoverages.get(0).getBeginCoverage(), equalTo("2004-03-01")); - assertThat(customCoverages.get(0).getEndCoverage(), equalTo("2004-03-04")); + var customCoverages = resource.getData().getAttributes().getCustomCoverages(); + assertEquals(2, customCoverages.size()); + assertEquals("2004-03-01", customCoverages.get(0).getBeginCoverage()); + assertEquals("2004-03-04", customCoverages.get(0).getEndCoverage()); - assertThat(customCoverages.get(1).getBeginCoverage(), equalTo("2001-01-01")); - assertThat(customCoverages.get(1).getEndCoverage(), equalTo("2004-02-01")); + assertEquals("2001-01-01", customCoverages.get(1).getBeginCoverage()); + assertEquals("2004-02-01", customCoverages.get(1).getEndCoverage()); } } diff --git a/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java b/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java index b6940feba..2f9f8d946 100644 --- a/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java +++ b/src/test/java/org/folio/rest/converter/resources/ResourceRequestConverterTest.java @@ -1,52 +1,51 @@ package org.folio.rest.converter.resources; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.folio.util.ResourcesTestUtil.getResourcePutRequest; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.Collections; import org.folio.holdingsiq.model.CoverageDates; import org.folio.holdingsiq.model.CustomerResources; -import org.folio.holdingsiq.model.ResourcePut; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.UserDefinedFields; import org.folio.holdingsiq.model.VisibilityInfo; -import org.folio.rest.impl.ResourcesTestData; import org.folio.rest.jaxrs.model.EmbargoPeriod; import org.folio.rest.jaxrs.model.EmbargoPeriod.EmbargoUnit; import org.folio.rest.jaxrs.model.Proxy; import org.folio.rest.jaxrs.model.ResourcePutDataAttributes; import org.folio.rest.jaxrs.model.VisibilityData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -public class ResourceRequestConverterTest { - - public static final String OLD_COVERAGE_STATEMENT = "statement"; - public static final String OLD_URL = "http://example.com"; - public static final boolean OLD_VISIBILITY_DATA = true; - public static final String OLD_BEGIN_COVERAGE = "2002-10-10"; - public static final String OLD_END_COVERAGE = "2003-10-10"; - public static final String OLD_EMBARGO_UNIT = "Day"; - public static final int OLD_EMBARGO_VALUE = 5; +class ResourceRequestConverterTest { + private static final boolean OLD_VISIBILITY_DATA = true; + private static final int OLD_EMBARGO_VALUE = 5; + private static final String OLD_BEGIN_COVERAGE = "2002-10-10"; + private static final String OLD_COVERAGE_STATEMENT = "statement"; + private static final String OLD_EMBARGO_UNIT = "Day"; + private static final String OLD_END_COVERAGE = "2003-10-10"; private static final String OLD_PROXY_ID = "<n>"; + private static final String OLD_URL = "https://example.com"; private final ResourceRequestConverter resourcesConverter = new ResourceRequestConverter(); private Title resourceData; - @Before - public void setUp() { + @BeforeEach + void setUp() { resourceData = Title.builder() - .contributorsList(Collections.emptyList()) - .customerResourcesList(Collections.singletonList(CustomerResources.builder() + .contributorsList(emptyList()) + .customerResourcesList(singletonList(CustomerResources.builder() .coverageStatement(OLD_COVERAGE_STATEMENT) .isSelected(false) .visibilityData(VisibilityInfo.builder() .isHidden(OLD_VISIBILITY_DATA).build()) - .customCoverageList(Collections.singletonList(CoverageDates.builder() + .customCoverageList(singletonList(CoverageDates.builder() .beginCoverage(OLD_BEGIN_COVERAGE).endCoverage(OLD_END_COVERAGE).build())) .customEmbargoPeriod(org.folio.holdingsiq.model.EmbargoPeriod.builder() .embargoUnit(OLD_EMBARGO_UNIT).embargoValue(OLD_EMBARGO_VALUE).build()) @@ -56,63 +55,58 @@ public void setUp() { .userDefinedFields(UserDefinedFields.builder().build()) .build() )) - .identifiersList(Collections.emptyList()) - .subjectsList(Collections.emptyList()) + .identifiersList(emptyList()) + .subjectsList(emptyList()) .titleId(1) .build(); } @Test - public void shouldCreateRequestToSelectManagedResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true)), resourceData); + void shouldCreateRequestToSelectManagedResource() { + var resourcePut = resourcesConverter.convertToRmApiResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true)), resourceData); assertTrue(resourcePut.getIsSelected()); } @Test - public void shouldCreateRequestToSelectCustomResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiCustomResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true)), resourceData); + void shouldCreateRequestToSelectCustomResource() { + var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true)), resourceData); assertTrue(resourcePut.getIsSelected()); } @Test - public void shouldCreateRequestToUpdateProxyForManagedResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withProxy(new Proxy() - .withId("test-proxy-id"))), resourceData); + void shouldCreateRequestToUpdateProxyForManagedResource() { + var resourcePut = resourcesConverter.convertToRmApiResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withProxy(new Proxy() + .withId("test-proxy-id"))), resourceData); assertEquals("test-proxy-id", resourcePut.getProxy().getId()); } @Test - public void shouldCreateRequestToUpdateProxyForCustomResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiCustomResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withProxy(new Proxy() - .withId("test-proxy-id"))), resourceData); + void shouldCreateRequestToUpdateProxyForCustomResource() { + var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withProxy(new Proxy() + .withId("test-proxy-id"))), resourceData); assertEquals("test-proxy-id", resourcePut.getProxy().getId()); } @Test - public void shouldCreateRequestToUpdateUserDefineFieldsForCustomResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiCustomResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withUserDefinedField1("test 1") - .withUserDefinedField2("test 2") - .withUserDefinedField3("test 3") - .withUserDefinedField4("test 4") - .withUserDefinedField5("test 5")), resourceData); + void shouldCreateRequestToUpdateUserDefineFieldsForCustomResource() { + var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withUserDefinedField1("test 1") + .withUserDefinedField2("test 2") + .withUserDefinedField3("test 3") + .withUserDefinedField4("test 4") + .withUserDefinedField5("test 5")), resourceData); assertEquals("test 1", resourcePut.getUserDefinedFields().getUserDefinedField1()); assertEquals("test 2", resourcePut.getUserDefinedFields().getUserDefinedField2()); assertEquals("test 3", resourcePut.getUserDefinedFields().getUserDefinedField3()); @@ -121,71 +115,65 @@ public void shouldCreateRequestToUpdateUserDefineFieldsForCustomResource() { } @Test - public void shouldCreateRequestToUpdateIsHiddenForCustomResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiCustomResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withVisibilityData(new VisibilityData() - .withIsHidden(true))), resourceData); + void shouldCreateRequestToUpdateIsHiddenForCustomResource() { + var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withVisibilityData(new VisibilityData() + .withIsHidden(true))), resourceData); assertTrue(resourcePut.getIsHidden()); } @Test - public void shouldCreateRequestToUpdateCoverageStatementForManagedResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withCoverageStatement("test coverage stmt")), resourceData); + void shouldCreateRequestToUpdateCoverageStatementForManagedResource() { + var resourcePut = resourcesConverter.convertToRmApiResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withCoverageStatement("test coverage stmt")), resourceData); assertEquals("test coverage stmt", resourcePut.getCoverageStatement()); } @Test - public void shouldCreateRequestToUpdateCoverageStatementForCustomResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiCustomResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withCoverageStatement("test coverage stmt")), resourceData); + void shouldCreateRequestToUpdateCoverageStatementForCustomResource() { + var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withCoverageStatement("test coverage stmt")), resourceData); assertEquals("test coverage stmt", resourcePut.getCoverageStatement()); } @Test - public void shouldCreateRequestToUpdateIsHiddenForManagedResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withVisibilityData(new VisibilityData() - .withIsHidden(false))), resourceData); + void shouldCreateRequestToUpdateIsHiddenForManagedResource() { + var resourcePut = resourcesConverter.convertToRmApiResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withVisibilityData(new VisibilityData() + .withIsHidden(false))), resourceData); assertFalse(resourcePut.getIsHidden()); } @Test - public void shouldCreateRequestToUpdateCustomEmbargoPeriodForManagedResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withCustomEmbargoPeriod(new EmbargoPeriod() - .withEmbargoUnit(EmbargoUnit.DAYS) - .withEmbargoValue(10))), resourceData); + void shouldCreateRequestToUpdateCustomEmbargoPeriodForManagedResource() { + var resourcePut = resourcesConverter.convertToRmApiResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withCustomEmbargoPeriod(new EmbargoPeriod() + .withEmbargoUnit(EmbargoUnit.DAYS) + .withEmbargoValue(10))), resourceData); assertEquals("Days", resourcePut.getCustomEmbargoPeriod().getEmbargoUnit()); assertEquals(10, resourcePut.getCustomEmbargoPeriod().getEmbargoValue()); } @Test - public void shouldCreateRequestToUpdateUserDefinedFieldsForManagedResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withUserDefinedField1("test 1") - .withUserDefinedField2("test 2") - .withUserDefinedField3("test 3") - .withUserDefinedField4("test 4") - .withUserDefinedField5("test 5")), resourceData); + void shouldCreateRequestToUpdateUserDefinedFieldsForManagedResource() { + var resourcePut = resourcesConverter.convertToRmApiResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withUserDefinedField1("test 1") + .withUserDefinedField2("test 2") + .withUserDefinedField3("test 3") + .withUserDefinedField4("test 4") + .withUserDefinedField5("test 5")), resourceData); assertEquals("test 1", resourcePut.getUserDefinedFields().getUserDefinedField1()); assertEquals("test 2", resourcePut.getUserDefinedFields().getUserDefinedField2()); assertEquals("test 3", resourcePut.getUserDefinedFields().getUserDefinedField3()); @@ -194,27 +182,25 @@ public void shouldCreateRequestToUpdateUserDefinedFieldsForManagedResource() { } @Test - public void shouldCreateRequestToUpdateCustomEmbargoPeriodForCustomResource() { - ResourcePut resourcePut = - resourcesConverter.convertToRmApiCustomResourcePutRequest(ResourcesTestData.getResourcePutRequest( - new ResourcePutDataAttributes() - .withIsSelected(true) - .withCustomEmbargoPeriod(new EmbargoPeriod() - .withEmbargoUnit(EmbargoUnit.YEARS) - .withEmbargoValue(10))), resourceData); + void shouldCreateRequestToUpdateCustomEmbargoPeriodForCustomResource() { + var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest( + new ResourcePutDataAttributes() + .withIsSelected(true) + .withCustomEmbargoPeriod(new EmbargoPeriod() + .withEmbargoUnit(EmbargoUnit.YEARS) + .withEmbargoValue(10))), resourceData); assertEquals("Years", resourcePut.getCustomEmbargoPeriod().getEmbargoUnit()); assertEquals(10, resourcePut.getCustomEmbargoPeriod().getEmbargoValue()); } @Test - public void shouldCreateRequestToUpdateUrlForCustomResource() { - CustomerResources.CustomerResourcesBuilder customerResourcesBuilder = - resourceData.getCustomerResourcesList().getFirst().toBuilder(); - CustomerResources resources = customerResourcesBuilder.isPackageCustom(true).build(); - Title title = resourceData.toBuilder().customerResourcesList(Collections.singletonList(resources)).build(); - - ResourcePut resourcePut = - resourcesConverter.convertToRmApiCustomResourcePutRequest(ResourcesTestData.getResourcePutRequest( + void shouldCreateRequestToUpdateUrlForCustomResource() { + var customerResourcesBuilder = resourceData.getCustomerResourcesList().getFirst().toBuilder(); + var resources = customerResourcesBuilder.isPackageCustom(true).build(); + var title = resourceData.toBuilder().customerResourcesList(singletonList(resources)).build(); + + var resourcePut = + resourcesConverter.convertToRmApiCustomResourcePutRequest(getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(true) .withUrl("test url")), title); @@ -222,13 +208,13 @@ public void shouldCreateRequestToUpdateUrlForCustomResource() { } @Test - public void shouldCreateRequestWithOldDataExceptEmbargoWhenUpdateFieldsAreMissing() { + void shouldCreateRequestWithOldDataExceptEmbargoWhenUpdateFieldsAreMissing() { var customerResourcesBuilder = resourceData.getCustomerResourcesList().getFirst().toBuilder(); var resources = customerResourcesBuilder.isPackageCustom(true).build(); - var title = resourceData.toBuilder().customerResourcesList(Collections.singletonList(resources)).build(); + var title = resourceData.toBuilder().customerResourcesList(singletonList(resources)).build(); var resourcePut = resourcesConverter.convertToRmApiCustomResourcePutRequest( - ResourcesTestData.getResourcePutRequest(new ResourcePutDataAttributes()), + getResourcePutRequest(new ResourcePutDataAttributes()), title ); assertEquals(OLD_PROXY_ID, resourcePut.getProxy().getId()); diff --git a/src/test/java/org/folio/rest/converter/titles/TitleCollectionConverterTest.java b/src/test/java/org/folio/rest/converter/titles/TitleCollectionConverterTest.java index c4230a762..74a19720e 100644 --- a/src/test/java/org/folio/rest/converter/titles/TitleCollectionConverterTest.java +++ b/src/test/java/org/folio/rest/converter/titles/TitleCollectionConverterTest.java @@ -1,9 +1,9 @@ package org.folio.rest.converter.titles; import static java.util.Collections.singletonList; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.util.List; import org.folio.holdingsiq.model.Facets; @@ -12,13 +12,12 @@ import org.folio.holdingsiq.model.Titles; import org.folio.rest.jaxrs.model.FacetsDto; import org.folio.rest.jaxrs.model.PackageFacetDto; -import org.folio.rest.jaxrs.model.TitleCollection; import org.folio.rest.jaxrs.model.TitleCollectionItem; import org.folio.rest.jaxrs.model.TitleCollectionItemDataAttributes; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.core.convert.converter.Converter; -public class TitleCollectionConverterTest { +class TitleCollectionConverterTest { private final Converter<Title, TitleCollectionItem> titleItemConverterMock = title -> new TitleCollectionItem() .withId(String.valueOf(title.getTitleId())) @@ -29,14 +28,15 @@ public class TitleCollectionConverterTest { .withPackages(singletonList(new PackageFacetDto() .withId(facets.getPackages().getFirst().getPackageId()) .withName(facets.getPackages().getFirst().getPackageName()))); - private final TitleCollectionConverter.FromTitles converter = new TitleCollectionConverter.FromTitles( - titleItemConverterMock, facetsConverterMock); + + private final TitleCollectionConverter.FromTitles converter = new TitleCollectionConverter + .FromTitles(titleItemConverterMock, facetsConverterMock); @Test - public void shouldConvertFromTitles() { - Titles titles = createTitles(); + void shouldConvertFromTitles() { + var titles = createTitles(); - TitleCollection titlesCollection = converter.convert(titles); + var titlesCollection = converter.convert(titles); assertNotNull(titlesCollection); assertEquals(titles.getTotalResults(), titlesCollection.getMeta().getTotalResults()); @@ -51,10 +51,10 @@ public void shouldConvertFromTitles() { } @Test - public void shouldConvertFromTitlesWithNullFacets() { - Titles titles = createTitles(null); + void shouldConvertFromTitlesWithNullFacets() { + var titles = createTitles(null); - TitleCollection titlesCollection = converter.convert(titles); + var titlesCollection = converter.convert(titles); assertNotNull(titlesCollection); assertEquals(titles.getTotalResults(), titlesCollection.getMeta().getTotalResults()); @@ -63,7 +63,7 @@ public void shouldConvertFromTitlesWithNullFacets() { } private Titles createTitles() { - Facets facets = Facets.builder() + var facets = Facets.builder() .packages(singletonList(PackageFacet.builder() .packageId(2) .packageName("test") diff --git a/src/test/java/org/folio/rest/converter/titles/TitlePutRequestConverterTest.java b/src/test/java/org/folio/rest/converter/titles/TitlePutRequestConverterTest.java index a35a9f8b4..321b59274 100644 --- a/src/test/java/org/folio/rest/converter/titles/TitlePutRequestConverterTest.java +++ b/src/test/java/org/folio/rest/converter/titles/TitlePutRequestConverterTest.java @@ -1,30 +1,46 @@ package org.folio.rest.converter.titles; -import static org.folio.rest.impl.ResourcesTestData.OLD_PROXY_ID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; -import org.folio.holdingsiq.model.ResourcePut; +import java.util.Collections; +import org.folio.holdingsiq.model.CoverageDates; +import org.folio.holdingsiq.model.CustomerResources; +import org.folio.holdingsiq.model.EmbargoPeriod; +import org.folio.holdingsiq.model.ProxyUrl; +import org.folio.holdingsiq.model.Title; +import org.folio.holdingsiq.model.UserDefinedFields; +import org.folio.holdingsiq.model.VisibilityInfo; import org.folio.rest.converter.common.attr.ContributorsConverterPair; import org.folio.rest.converter.common.attr.IdentifiersConverterPair; -import org.folio.rest.impl.ResourcesTestData; import org.folio.rest.jaxrs.model.PublicationType; import org.folio.rest.jaxrs.model.TitlePutData; import org.folio.rest.jaxrs.model.TitlePutDataAttributes; import org.folio.rest.jaxrs.model.TitlePutRequest; -import org.junit.Test; +import org.folio.rmapi.result.ResourceResult; +import org.junit.jupiter.api.Test; + +class TitlePutRequestConverterTest { + + private static final boolean OLD_VISIBILITY_DATA = true; + private static final int OLD_EMBARGO_VALUE = 5; + private static final String OLD_BEGIN_COVERAGE = "2002-10-10"; + private static final String OLD_COVERAGE_STATEMENT = "statement"; + private static final String OLD_EMBARGO_UNIT = "Day"; + private static final String OLD_END_COVERAGE = "2003-10-10"; + private static final String OLD_PROXY_ID = "<n>"; + private static final String OLD_URL = "http://example.com"; -public class TitlePutRequestConverterTest { private final TitlePutRequestConverter converter = new TitlePutRequestConverter( new IdentifiersConverterPair.ToRmApi(), new ContributorsConverterPair.ToRmApi()); @Test - public void shouldCreateRequestToUpdatePublicationTypeForCustomResource() { - TitlePutRequest request = createEmptyTitlePutRequest(); + void shouldCreateRequestToUpdatePublicationTypeForCustomResource() { + var request = createEmptyTitlePutRequest(); request.getData().getAttributes().setPublicationType(PublicationType.BOOK_SERIES); - ResourcePut resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, - ResourcesTestData.createResourceData().getTitle().getCustomerResourcesList().getFirst()); + var resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, + createResourceData().getTitle().getCustomerResourcesList().getFirst()); assertEquals("bookseries", resourcePut.getPubType()); //from ProxyUrl to Proxy assertEquals(OLD_PROXY_ID, resourcePut.getProxy().getId()); @@ -32,50 +48,75 @@ public void shouldCreateRequestToUpdatePublicationTypeForCustomResource() { } @Test - public void shouldCreateRequestToUpdateIsPeerReviewedForCustomResource() { - TitlePutRequest request = createEmptyTitlePutRequest(); + void shouldCreateRequestToUpdateIsPeerReviewedForCustomResource() { + var request = createEmptyTitlePutRequest(); request.getData().getAttributes().setIsPeerReviewed(false); - ResourcePut resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, - ResourcesTestData.createResourceData().getTitle().getCustomerResourcesList().getFirst()); + var resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, + createResourceData().getTitle().getCustomerResourcesList().getFirst()); assertFalse(resourcePut.getIsPeerReviewed()); } @Test - public void shouldCreateRequestToUpdateResourceNameForCustomResource() { - TitlePutRequest request = createEmptyTitlePutRequest(); + void shouldCreateRequestToUpdateResourceNameForCustomResource() { + var request = createEmptyTitlePutRequest(); request.getData().getAttributes().setName("test name"); - ResourcePut resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, - ResourcesTestData.createResourceData().getTitle().getCustomerResourcesList().getFirst()); + var resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, + createResourceData().getTitle().getCustomerResourcesList().getFirst()); assertEquals("test name", resourcePut.getTitleName()); } @Test - public void shouldCreateRequestToUpdatePublisherNameForCustomResource() { - TitlePutRequest request = createEmptyTitlePutRequest(); + void shouldCreateRequestToUpdatePublisherNameForCustomResource() { + var request = createEmptyTitlePutRequest(); request.getData().getAttributes().setPublisherName("test pub name"); - ResourcePut resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, - ResourcesTestData.createResourceData().getTitle().getCustomerResourcesList().getFirst()); + var resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, + createResourceData().getTitle().getCustomerResourcesList().getFirst()); assertEquals("test pub name", resourcePut.getPublisherName()); } @Test - public void shouldCreateRequestToUpdateEditionForCustomResource() { - TitlePutRequest request = createEmptyTitlePutRequest(); + void shouldCreateRequestToUpdateEditionForCustomResource() { + var request = createEmptyTitlePutRequest(); request.getData().getAttributes().setEdition("test edition"); - ResourcePut resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, - ResourcesTestData.createResourceData().getTitle().getCustomerResourcesList().getFirst()); + var resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, + createResourceData().getTitle().getCustomerResourcesList().getFirst()); assertEquals("test edition", resourcePut.getEdition()); } @Test - public void shouldCreateRequestToUpdateDescriptionForCustomResource() { - TitlePutRequest request = createEmptyTitlePutRequest(); + void shouldCreateRequestToUpdateDescriptionForCustomResource() { + var request = createEmptyTitlePutRequest(); request.getData().getAttributes().setDescription("test description"); - ResourcePut resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, - ResourcesTestData.createResourceData().getTitle().getCustomerResourcesList().getFirst()); + var resourcePut = converter.convertToRmApiCustomResourcePutRequest(request, + createResourceData().getTitle().getCustomerResourcesList().getFirst()); assertEquals("test description", resourcePut.getDescription()); } + private ResourceResult createResourceData() { + var title = Title.builder() + .contributorsList(Collections.emptyList()) + .customerResourcesList(Collections.singletonList(CustomerResources.builder() + .coverageStatement(OLD_COVERAGE_STATEMENT) + .isSelected(false) + .visibilityData(VisibilityInfo.builder() + .isHidden(OLD_VISIBILITY_DATA).build()) + .customCoverageList(Collections.singletonList(CoverageDates.builder() + .beginCoverage(OLD_BEGIN_COVERAGE).endCoverage(OLD_END_COVERAGE).build())) + .customEmbargoPeriod(EmbargoPeriod.builder() + .embargoUnit(OLD_EMBARGO_UNIT).embargoValue(OLD_EMBARGO_VALUE).build()) + .proxy(ProxyUrl.builder().proxiedUrl(OLD_URL) + .id(OLD_PROXY_ID).inherited(true).build()) + .url(OLD_URL) + .userDefinedFields(UserDefinedFields.builder().build()) + .build() + )) + .identifiersList(Collections.emptyList()) + .subjectsList(Collections.emptyList()) + .titleId(1) + .build(); + return new ResourceResult(title, null, null, false); + } + private TitlePutRequest createEmptyTitlePutRequest() { TitlePutRequest request = new TitlePutRequest(); request.setData(new TitlePutData()); diff --git a/src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java new file mode 100644 index 000000000..15e5f1b2e --- /dev/null +++ b/src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java @@ -0,0 +1,476 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static org.folio.HttpStatus.SC_CONFLICT; +import static org.folio.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.repository.holdings.status.HoldingsLoadingStatusFactory.getStatusCompleted; +import static org.folio.repository.holdings.status.HoldingsLoadingStatusFactory.getStatusLoadingHoldings; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.rest.util.DateTimeUtil.POSTGRES_TIMESTAMP_FORMATTER; +import static org.folio.rest.util.DateTimeUtil.POSTGRES_TIMESTAMP_OLD_FORMATTER; +import static org.folio.service.holdings.HoldingConstants.CREATE_SNAPSHOT_ACTION; +import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; +import static org.folio.service.holdings.HoldingConstants.LOAD_FACADE_ADDRESS; +import static org.folio.service.holdings.HoldingConstants.SAVE_HOLDINGS_ACTION; +import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; +import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_FAILED_ACTION; +import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; +import static org.folio.util.HoldingsStatusAuditTestUtil.saveStatusAudit; +import static org.folio.util.HoldingsStatusUtil.PROCESS_ID; +import static org.folio.util.HoldingsStatusUtil.saveStatus; +import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.interceptAndContinue; +import static org.folio.util.TestUtil.interceptAndStop; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.result; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasProperty; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; + +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.matching.UrlPathPattern; +import io.vertx.core.Handler; +import io.vertx.core.eventbus.DeliveryContext; +import io.vertx.core.json.JsonObject; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import lombok.SneakyThrows; +import org.folio.holdingsiq.model.Configuration; +import org.folio.repository.holdings.status.HoldingsStatusRepositoryImpl; +import org.folio.repository.holdings.status.retry.RetryStatusRepository; +import org.folio.rest.jaxrs.model.LoadStatusAttributes; +import org.folio.rest.jaxrs.model.LoadStatusNameDetailEnum; +import org.folio.rest.jaxrs.model.LoadStatusNameEnum; +import org.folio.service.holdings.HoldingsService; +import org.folio.service.holdings.LoadServiceFacade; +import org.folio.service.holdings.message.HoldingsMessage; +import org.folio.service.holdings.message.LoadHoldingsMessage; +import org.folio.util.HoldingsStatusAuditTestUtil; +import org.folio.util.HoldingsStatusUtil; +import org.folio.util.HoldingsTestUtil; +import org.folio.util.IntegrationTestBase; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.util.ReflectionTestUtils; + +class DefaultLoadHoldingsImplIntegrationTest extends IntegrationTestBase { + + public static final String HOLDINGS_LOAD_URL = "/eholdings/loading/kb-credentials"; + public static final String HOLDINGS_LOAD_BY_ID_URL = HOLDINGS_LOAD_URL + "/" + STUB_CREDENTIALS_ID; + + // RM API responses + private static final String RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED = + "responses/rmapi/holdings/status/get-status-completed.json"; + private static final String RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED_ONE_PAGE = + "responses/rmapi/holdings/status/get-status-completed-one-page.json"; + private static final String RMAPI_RESPONSE_HOLDINGS = + "responses/rmapi/holdings/holdings/get-holdings.json"; + + private static final int TIMEOUT = 180000; + private static final int EXPECTED_LOADED_PAGES = 2; + private static final int TEST_SNAPSHOT_RETRY_COUNT = 2; + private static final String STUB_HOLDINGS_TITLE = "java-test-one"; + + @Autowired + HoldingsService holdingsService; + @Autowired + HoldingsStatusRepositoryImpl holdingsStatusRepository; + @Autowired + RetryStatusRepository retryStatusRepository; + private Configuration stubConfiguration; + private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; + + @BeforeEach + void setUp() { + stubConfiguration = Configuration.builder() + .apiKey(STUB_API_KEY) + .customerId(STUB_CUSTOMER_ID) + .url(getWiremockUrl()) + .build(); + holdingsStatusRepository = spy(holdingsStatusRepository); + ReflectionTestUtils.setField(holdingsService, "holdingsStatusRepository", holdingsStatusRepository); + } + + @AfterEach + void tearDown() { + if (interceptor != null) { + vertx.eventBus().removeOutboundInterceptor(interceptor); + } + tearDownHoldingsData(); + } + + @Test + void shouldSaveHoldings() { + setupDefaultLoadKbConfiguration(); + runPostHoldingsWithMocks(); + + var holdingsList = HoldingsTestUtil.getHoldings(vertx); + assertFalse(holdingsList.isEmpty()); + } + + @Test + void shouldSaveMultiHoldings() { + setupDefaultLoadKbConfiguration(); + var latch = new CountDownLatch(1); + handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + + mockGet(WireMock.equalTo(holdingsStatusRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); + mockPostHoldings(); + mockGet(WireMock.matching(postHoldingsRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS)); + + postWithStatus(HOLDINGS_LOAD_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + + var holdingsList = HoldingsTestUtil.getHoldings(vertx); + assertFalse(holdingsList.isEmpty()); + } + + @Test + void shouldSaveMultiHoldingsWhenSnapshotNotCreated() { + setupDefaultLoadKbConfiguration(); + var latch = new CountDownLatch(1); + handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + + var errorResponse = new ResponseDefinitionBuilder().withStatus(500); + var emptyResponse = new ResponseDefinitionBuilder().withBody(""); + var successfulResponse = new ResponseDefinitionBuilder() + .withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); + + mockResponseList(new UrlPathPattern(WireMock.equalTo(holdingsStatusRmApi()), false), + errorResponse, emptyResponse, successfulResponse); + + mockPostHoldings(); + mockGet(WireMock.matching(postHoldingsRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS)); + + postWithStatus(HOLDINGS_LOAD_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + + var holdingsList = HoldingsTestUtil.getHoldings(vertx); + assertFalse(holdingsList.isEmpty()); + } + + @Test + void shouldNotStartLoadingWhenStatusInProgress() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveStatus(STUB_CREDENTIALS_ID, getStatusLoadingHoldings(1000, 500, 10, 5), PROCESS_ID, vertx); + interceptor = interceptAndStop(LOAD_FACADE_ADDRESS, CREATE_SNAPSHOT_ACTION, message -> { }); + vertx.eventBus().addOutboundInterceptor(interceptor); + var statusCode = postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_CONFLICT).statusCode(); + assertEquals(SC_CONFLICT, statusCode); + } + + @Test + void shouldStartLoadingWithOldDateFormat() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + var dateTime = OffsetDateTime.now().minusDays(6); + var status = getStatusLoadingHoldings(1000, 500, 10, 5); + status.getData().getAttributes().setStarted(dateTime.format(POSTGRES_TIMESTAMP_OLD_FORMATTER)); + status.getData().getAttributes().setUpdated(dateTime.format(POSTGRES_TIMESTAMP_OLD_FORMATTER)); + saveStatus(STUB_CREDENTIALS_ID, status, PROCESS_ID, vertx); + + insertRetryStatus(STUB_CREDENTIALS_ID, vertx); + runPostHoldingsWithMocks(); + + var holdingsList = HoldingsTestUtil.getHoldings(vertx); + assertFalse(holdingsList.isEmpty()); + } + + @Test + void shouldStartLoadingWhenStatusInProgressAndStartedMoreThen5DaysBefore() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + var dateTime = OffsetDateTime.now().minusDays(6); + var statusLoadingHoldings = getStatusLoadingHoldings(1000, 500, 10, 5); + statusLoadingHoldings.getData().getAttributes().setStarted(dateTime.format(POSTGRES_TIMESTAMP_FORMATTER)); + statusLoadingHoldings.getData().getAttributes().setUpdated(dateTime.format(POSTGRES_TIMESTAMP_FORMATTER)); + saveStatus(STUB_CREDENTIALS_ID, statusLoadingHoldings, PROCESS_ID, vertx); + + insertRetryStatus(STUB_CREDENTIALS_ID, vertx); + runPostHoldingsWithMocks(); + + var holdingsList = HoldingsTestUtil.getHoldings(vertx); + assertFalse(holdingsList.isEmpty()); + } + + @Test + void shouldSaveStatusChangesToAuditTable() { + setupDefaultLoadKbConfiguration(); + + runPostHoldingsWithMocks(); + var attributes = HoldingsStatusAuditTestUtil.getRecords(vertx) + .stream().map(status -> status.getData().getAttributes()).toList(); + + assertThat(attributes, containsInAnyOrder( + statusEquals(LoadStatusNameEnum.NOT_STARTED), + statusEquals(LoadStatusNameEnum.NOT_STARTED), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 0), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 1), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 2), + statusEquals(LoadStatusNameEnum.COMPLETED) + ) + ); + } + + @Test + void shouldClearOldStatusChangeRecords() { + setupDefaultLoadKbConfiguration(); + saveStatusAudit(STUB_CREDENTIALS_ID, getStatusCompleted(1000), + OffsetDateTime.now().minusDays(60), vertx); + + interceptor = interceptAndStop(LOAD_FACADE_ADDRESS, CREATE_SNAPSHOT_ACTION, message -> { }); + vertx.eventBus().addOutboundInterceptor(interceptor); + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + var attributes = HoldingsStatusAuditTestUtil.getRecords(vertx) + .stream().map(status -> status.getData().getAttributes()).toList(); + assertEquals(3, attributes.size()); + assertThat(attributes, containsInAnyOrder( + statusEquals(LoadStatusNameEnum.NOT_STARTED), //insert + statusEquals(LoadStatusNameEnum.NOT_STARTED), //delete + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null) + )); + } + + @Test + void shouldStartLoadingWhenStatusInProgressAndProcessTimedOut() { + setupDefaultLoadKbConfiguration(); + var status = getStatusLoadingHoldings(1000, 500, 10, 5); + + var dateTime = OffsetDateTime.now().minusDays(10); + status.getData().getAttributes().setUpdated(POSTGRES_TIMESTAMP_FORMATTER.format(dateTime)); + saveStatus(STUB_CREDENTIALS_ID, status, PROCESS_ID, vertx); + + interceptor = interceptAndStop(LOAD_FACADE_ADDRESS, CREATE_SNAPSHOT_ACTION, message -> { }); + vertx.eventBus().addOutboundInterceptor(interceptor); + var statusCode = postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT).statusCode(); + assertEquals(SC_NO_CONTENT, statusCode); + } + + @Test + void shouldRetryCreationOfSnapshotWhenItFails() { + setupDefaultLoadKbConfiguration(); + + mockPost(WireMock.equalTo(postHoldingsRmApi()), "", 202); + var failedResponse = new ResponseDefinitionBuilder().withStatus(500); + var successfulResponse = new ResponseDefinitionBuilder() + .withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); + mockResponseList(new UrlPathPattern(WireMock.equalTo(holdingsStatusRmApi()), false), + failedResponse, successfulResponse, successfulResponse); + + var latch = new CountDownLatch(1); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + } + + @Test + void shouldStopRetryingAfterMultipleFailures() { + setupDefaultLoadKbConfiguration(); + + mockGet(WireMock.equalTo(holdingsStatusRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); + mockPost(WireMock.equalTo(postHoldingsRmApi()), "", 500); + + var latch = new CountDownLatch(TEST_SNAPSHOT_RETRY_COUNT); + interceptor = interceptAndContinue(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_FAILED_ACTION, o -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + + var status = + result(retryStatusRepository.findByCredentialsId(UUID.fromString(STUB_CREDENTIALS_ID), STUB_TENANT)); + var timerExists = vertx.cancelTimer(status.getTimerId()); + assertEquals(0, status.getRetryAttemptsLeft()); + assertFalse(timerExists); + + verifyPost(WireMock.equalTo(postHoldingsRmApi()), TEST_SNAPSHOT_RETRY_COUNT); + } + + @Test + void shouldRetryLoadingHoldingsFromStartWhenPageFailsToLoad() { + setupDefaultLoadKbConfiguration(); + mockGet(WireMock.equalTo(holdingsStatusRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); + + mockPost(WireMock.equalTo(postHoldingsRmApi()), "", 202); + + var successResponse = new ResponseDefinitionBuilder() + .withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) + .withStatus(200); + var failResponse = new ResponseDefinitionBuilder().withStatus(500); + mockResponseList(urlPathEqualTo(postHoldingsRmApi()), successResponse, failResponse, failResponse, successResponse); + + var firstTryPages = 1; + var secondTryPages = 2; + var latch = new CountDownLatch(firstTryPages + secondTryPages); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + } + + @Test + void shouldSendSaveHoldingsEventForEachLoadedPage() { + mockGet(WireMock.equalTo(holdingsStatusRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); + mockGet(WireMock.matching(postHoldingsRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS)); + + var messages = new ArrayList<HoldingsMessage>(); + var latch = new CountDownLatch(EXPECTED_LOADED_PAGES); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, + message -> { + messages.add(((JsonObject) message.body()).getJsonObject("holdings").mapTo(HoldingsMessage.class)); + latch.countDown(); + }); + vertx.eventBus().addOutboundInterceptor(interceptor); + + var proxy = LoadServiceFacade.createProxy(vertx, LOAD_FACADE_ADDRESS); + proxy.loadHoldings( + new LoadHoldingsMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT, 5001, 2, null, null)); + + assertLatch(latch); + assertEquals(2, messages.size()); + assertEquals(STUB_HOLDINGS_TITLE, messages.getFirst().getHoldingList().getFirst().getPublicationTitle()); + } + + @Test + void shouldRetryLoadingPageWhenPageFails() { + setupDefaultLoadKbConfiguration(); + var latch = new CountDownLatch(1); + handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + mockGet(WireMock.equalTo(holdingsStatusRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED_ONE_PAGE)); + + mockPostHoldings(); + mockResponseList(new UrlPathPattern(WireMock.equalTo(postHoldingsRmApi()), false), + new ResponseDefinitionBuilder().withStatus(SC_INTERNAL_SERVER_ERROR), + new ResponseDefinitionBuilder().withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) + ); + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + assertLatch(latch); + } + + @Test + @SuppressWarnings("checkstyle:methodLength") + void shouldRetryCreationOfSnapshotAndUpdateHoldingsStatusWhenItFails() { + setupDefaultLoadKbConfiguration(); + var latch = new CountDownLatch(1); + handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + var failResponse = new ResponseDefinitionBuilder().withStatus(500); + var successResponse = new ResponseDefinitionBuilder() + .withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED_ONE_PAGE)); + mockResponseList(urlPathEqualTo(holdingsStatusRmApi()), failResponse, successResponse, successResponse); + mockPostHoldings(); + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + mockGet(WireMock.matching(postHoldingsRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS)); + + assertLatch(latch); + var attributes = HoldingsStatusAuditTestUtil.getRecords(vertx) + .stream().map(status -> status.getData().getAttributes()).toList(); + assertThat(attributes, containsInAnyOrder( + statusEquals(LoadStatusNameEnum.NOT_STARTED), + statusEquals(LoadStatusNameEnum.NOT_STARTED), + statusEquals(LoadStatusNameEnum.FAILED), + statusEquals(LoadStatusNameEnum.FAILED), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 0), + statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 1), + statusEquals(LoadStatusNameEnum.COMPLETED) + )); + + var holdingsLoadingStatus = HoldingsStatusUtil.getStatus(STUB_CREDENTIALS_ID, vertx); + assertThat(holdingsLoadingStatus.getData().getAttributes(), statusEquals(LoadStatusNameEnum.COMPLETED)); + } + + static void handleStatusCompleted(HoldingsStatusRepositoryImpl repositorySpy, + Consumer<Void> handler) { + doAnswer(invocationOnMock -> { + @SuppressWarnings("unchecked") + CompletableFuture<Void> future = (CompletableFuture<Void>) invocationOnMock.callRealMethod(); + return future.thenAccept(handler); + }).when(repositorySpy).update( + argThat(argument -> argument.getData().getAttributes().getStatus().getName() + == LoadStatusNameEnum.COMPLETED), any(UUID.class), + anyString()); + } + + static void assertLatch(CountDownLatch latch) { + try { + assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private void setupDefaultLoadKbConfiguration() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); + insertRetryStatus(STUB_CREDENTIALS_ID, vertx); + } + + @SneakyThrows + private void runPostHoldingsWithMocks() { + var latch = new CountDownLatch(1); + handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + + mockGet(WireMock.equalTo(holdingsStatusRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); + mockPostHoldings(); + mockGet(WireMock.matching(postHoldingsRmApi()), readFile(RMAPI_RESPONSE_HOLDINGS)); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + } + + private void mockPostHoldings() { + mockPost(WireMock.equalTo(postHoldingsRmApi()), "", 202); + } + + private Matcher<LoadStatusAttributes> statusEquals(LoadStatusNameEnum status) { + return statusEquals(status, null, null); + } + + private Matcher<LoadStatusAttributes> statusEquals(LoadStatusNameEnum status, LoadStatusNameDetailEnum detail, + Integer importedPages) { + return allOf( + hasProperty("status", hasProperty("name", equalTo(status))), + hasProperty("status", hasProperty("detail", equalTo(detail))), + hasProperty("importedPages", equalTo(importedPages)) + ); + } + + private void tearDownHoldingsData() { + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } +} diff --git a/src/test/java/org/folio/rest/impl/DefaultLoadServiceFacadeIntegrationTest.java b/src/test/java/org/folio/rest/impl/DefaultLoadServiceFacadeIntegrationTest.java new file mode 100644 index 000000000..fe2b10c7a --- /dev/null +++ b/src/test/java/org/folio/rest/impl/DefaultLoadServiceFacadeIntegrationTest.java @@ -0,0 +1,126 @@ +package org.folio.rest.impl; + +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.service.holdings.AbstractLoadServiceFacade.HOLDINGS_STATUS_TIME_FORMATTER; +import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; +import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; +import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; +import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.interceptAndStop; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.matching.EqualToPattern; +import com.github.tomakehurst.wiremock.matching.UrlPathPattern; +import io.vertx.core.Handler; +import io.vertx.core.eventbus.DeliveryContext; +import io.vertx.core.json.Json; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.folio.holdingsiq.model.Configuration; +import org.folio.holdingsiq.model.HoldingsLoadStatus; +import org.folio.service.holdings.DefaultLoadServiceFacade; +import org.folio.service.holdings.message.ConfigurationMessage; +import org.folio.service.holdings.message.LoadHoldingsMessage; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class DefaultLoadServiceFacadeIntegrationTest extends IntegrationTestBase { + + // RM API responses + private static final String RMAPI_RESPONSE_HOLDINGS_STATUS_NONE = + "responses/rmapi/holdings/status/get-status-none.json"; + private static final String RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED = + "responses/rmapi/holdings/status/get-status-completed.json"; + + private static final int TIMEOUT = 60000; + + @Autowired + private DefaultLoadServiceFacade loadServiceFacade; + private Configuration configuration; + private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; + + @BeforeEach + void setUp() { + configuration = Configuration.builder() + .apiKey(STUB_API_KEY) + .customerId(STUB_CUSTOMER_ID) + .url(getWiremockUrl()) + .build(); + setupDefaultLoadKbConfiguration(); + } + + @AfterEach + void tearDown() { + if (interceptor != null) { + vertx.eventBus().removeOutboundInterceptor(interceptor); + } + tearDownHoldingsData(); + } + + @Test + void shouldCreateSnapshotOnInitialStatusNone() throws Exception { + var latch = new CountDownLatch(1); + + mockResponseList(new UrlPathPattern(new EqualToPattern(holdingsStatusRmApi()), false), + new ResponseDefinitionBuilder().withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_NONE)), + new ResponseDefinitionBuilder().withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)) + ); + mockPostHoldings(); + + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, + message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + loadServiceFacade.createSnapshot( + new ConfigurationMessage(configuration, STUB_CREDENTIALS_ID, STUB_TENANT)); + + assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } + + @Test + void shouldNotCreateSnapshotIfItWasRecentlyCreated() throws Exception { + var latch = new CountDownLatch(1); + + var now = HOLDINGS_STATUS_TIME_FORMATTER.format(LocalDateTime.now(ZoneOffset.UTC)); + var status = readJsonFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED, HoldingsLoadStatus.class) + .toBuilder().created(now).build(); + var urlPattern = new EqualToPattern(holdingsStatusRmApi()); + mockGet(urlPattern, Json.encode(status)); + mockPostHoldings(); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, + message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + loadServiceFacade.createSnapshot( + new ConfigurationMessage(configuration, STUB_CREDENTIALS_ID, STUB_TENANT)); + + latch.await(TIMEOUT, TimeUnit.MILLISECONDS); + + verifyPost(new EqualToPattern(postHoldingsRmApi()), 0); + } + + private void setupDefaultLoadKbConfiguration() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); + insertRetryStatus(STUB_CREDENTIALS_ID, vertx); + } + + private void mockPostHoldings() { + mockPost(new EqualToPattern(postHoldingsRmApi()), "", 202); + } + + private void tearDownHoldingsData() { + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } +} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAccessTypesImplTest.java b/src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java similarity index 65% rename from src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAccessTypesImplTest.java rename to src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java index 5ee160a6b..5ad279af7 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAccessTypesImplTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java @@ -1,21 +1,14 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.ok; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_CREATED; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; +package org.folio.rest.impl; + +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_CREATED; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.STUB_TOKEN; -import static org.folio.test.util.TestUtil.readFile; import static org.folio.util.AccessTypesTestUtil.ACCESS_TYPES_PATH; import static org.folio.util.AccessTypesTestUtil.KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT; import static org.folio.util.AccessTypesTestUtil.KB_CREDENTIALS_ACCESS_TYPE_ID_ENDPOINT; @@ -26,35 +19,28 @@ import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; import static org.folio.util.AccessTypesTestUtil.testData; import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.TokenTestUtils.generateToken; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TOKEN; +import static org.folio.util.TestUtil.clearDataFromTable; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.RegexPattern; import io.restassured.RestAssured; -import io.restassured.http.Header; import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; import java.util.List; import java.util.UUID; import org.folio.okapi.common.XOkapiHeaders; import org.folio.repository.RecordType; -import org.folio.rest.impl.WireMockTestBase; import org.folio.rest.jaxrs.model.AccessType; import org.folio.rest.jaxrs.model.AccessTypeCollection; import org.folio.rest.jaxrs.model.AccessTypeDataAttributes; @@ -62,68 +48,34 @@ import org.folio.rest.jaxrs.model.AccessTypePutRequest; import org.folio.rest.jaxrs.model.Errors; import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.test.util.TestUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) -public class EholdingsAccessTypesImplTest extends WireMockTestBase { - - private static final String USER_8 = "88888888-8888-4888-8888-888888888888"; - private static final String USER_9 = "99999999-9999-4999-9999-999999999999"; - private static final String USER_2 = "22222222-2222-4222-2222-222222222222"; - private static final String USER_3 = "33333333-3333-4333-3333-333333333333"; - - private static final Header USER8_TOKEN = new Header(XOkapiHeaders.TOKEN, generateToken("username", USER_8)); - private static final Header USER8_ID = new Header(XOkapiHeaders.USER_ID, USER_8); - private static final Header USER9_TOKEN = new Header(XOkapiHeaders.TOKEN, generateToken("username", USER_9)); - private static final Header USER9_ID = new Header(XOkapiHeaders.USER_ID, USER_9); - private static final Header USER2_TOKEN = new Header(XOkapiHeaders.TOKEN, generateToken("username", USER_2)); - private static final Header USER2_ID = new Header(XOkapiHeaders.USER_ID, USER_2); - private static final String USERDATA_COLLECTION_INFO_STUB_FILE = - "responses/userlookup/mock_user_collection_response_200.json"; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; - private String credentialsId; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - stubFor(get(urlPathEqualTo("/users/" + USER_8)) - .willReturn(ok(readFile("responses/userlookup/mock_user_response_200.json")))); - - stubFor(get(urlPathEqualTo("/users/" + USER_9)) - .willReturn(ok(readFile("responses/userlookup/mock_user_response_2_200.json")))); - - stubFor(get(urlPathEqualTo("/users/" + USER_2)) - .willReturn(new ResponseDefinitionBuilder().withStatus(404))); +class EholdingsAccessTypesImplIntegrationTest extends IntegrationTestBase { - stubFor(get(urlPathEqualTo("/users/" + USER_3)) - .willReturn(new ResponseDefinitionBuilder().withStatus(403))); - - stubFor(get(urlPathEqualTo("/users")) - .withQueryParam("query", new RegexPattern("id.*")) - .willReturn(ok(TestUtil.readFile(USERDATA_COLLECTION_INFO_STUB_FILE)))); + private String credentialsId; - credentialsId = saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + @BeforeEach + void setUp() { + credentialsId = setupDefaultKbConfiguration(getWiremockUrl(), vertx); } - @After - public void tearDown() { + @AfterEach + void tearDown() { clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); } @Test - public void shouldReturnAccessTypeCollectionOnGet() { + void shouldReturnAccessTypeCollectionOnGet() { List<AccessType> testAccessTypes = testData(credentialsId); final String id0 = insertAccessType(testAccessTypes.get(0), vertx); final String id1 = insertAccessType(testAccessTypes.get(1), vertx); - AccessTypeCollection actual = getWithStatus(ACCESS_TYPES_PATH, SC_OK, STUB_USER_ID_HEADER) + AccessTypeCollection actual = getWithStatus(ACCESS_TYPES_PATH, SC_OK) .as(AccessTypeCollection.class); assertEquals(Integer.valueOf(2), actual.getMeta().getTotalResults()); @@ -139,7 +91,7 @@ public void shouldReturnAccessTypeCollectionOnGet() { } @Test - public void shouldReturnAccessTypeCollectionOnGetByCredentialsId() { + void shouldReturnAccessTypeCollectionOnGetByCredentialsId() { List<AccessType> testAccessTypes = testData(credentialsId); final String id0 = insertAccessType(testAccessTypes.get(0), vertx); final String id1 = insertAccessType(testAccessTypes.get(1), vertx); @@ -160,7 +112,7 @@ public void shouldReturnAccessTypeCollectionOnGetByCredentialsId() { } @Test - public void shouldReturnAccessTypeCollectionWithUsageNumberOnGetByCredentialsId() { + void shouldReturnAccessTypeCollectionWithUsageNumberOnGetByCredentialsId() { List<AccessType> testAccessTypes = testData(credentialsId); final String id0 = insertAccessType(testAccessTypes.get(0), vertx); final String id1 = insertAccessType(testAccessTypes.get(1), vertx); @@ -175,13 +127,13 @@ public void shouldReturnAccessTypeCollectionWithUsageNumberOnGetByCredentialsId( String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); AccessTypeCollection actual = getWithOk(resourcePath).as(AccessTypeCollection.class); - assertThat(findAccessTypeWithId(actual, id0).getUsageNumber(), equalTo(3)); - assertThat(findAccessTypeWithId(actual, id1).getUsageNumber(), equalTo(2)); - assertThat(findAccessTypeWithId(actual, id2).getUsageNumber(), equalTo(0)); + assertEquals(3, findAccessTypeWithId(actual, id0).getUsageNumber()); + assertEquals(2, findAccessTypeWithId(actual, id1).getUsageNumber()); + assertEquals(0, findAccessTypeWithId(actual, id2).getUsageNumber()); } @Test - public void shouldReturnAccessTypeOnGetByIdAndUser() { + void shouldReturnAccessTypeOnGetByIdAndUser() { List<AccessType> accessTypes = testData(credentialsId); AccessType expected = accessTypes.getFirst(); String id = insertAccessType(expected, vertx); @@ -191,7 +143,7 @@ public void shouldReturnAccessTypeOnGetByIdAndUser() { insertAccessTypeMapping("11111111-1113", RecordType.PACKAGE, id, vertx); String resourcePath = ACCESS_TYPES_PATH + "/" + id; - AccessType actual = getWithStatus(resourcePath, SC_OK, STUB_USER_ID_HEADER).as(AccessType.class); + AccessType actual = getWithStatus(resourcePath, SC_OK).as(AccessType.class); assertEquals(id, actual.getId()); assertEquals(expected.getAttributes(), actual.getAttributes()); @@ -199,7 +151,7 @@ public void shouldReturnAccessTypeOnGetByIdAndUser() { } @Test - public void shouldReturnAccessTypeOnGetByIdAndCredentialsId() { + void shouldReturnAccessTypeOnGetByIdAndCredentialsId() { List<AccessType> accessTypes = testData(credentialsId); AccessType expected = accessTypes.getFirst(); String id = insertAccessType(expected, vertx); @@ -217,35 +169,35 @@ public void shouldReturnAccessTypeOnGetByIdAndCredentialsId() { } @Test - public void shouldReturn404OnGetByIdAndUserIfAccessTypeIsMissing() { + void shouldReturn404OnGetByIdAndUserIfAccessTypeIsMissing() { String id = "11111111-1111-1111-a111-111111111111"; String resourcePath = ACCESS_TYPES_PATH + "/" + id; - JsonapiError error = getWithStatus(resourcePath, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); + JsonapiError error = getWithStatus(resourcePath, SC_NOT_FOUND).as(JsonapiError.class); assertErrorContainsTitle(error, String.format("Access type not found: id = %s", id)); } @Test - public void shouldReturn404OnGetByIdAndCredentialsIfCredentialsIsMissing() { + void shouldReturn404OnGetByIdAndCredentialsIfCredentialsIsMissing() { String id = UUID.randomUUID().toString(); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPE_ID_ENDPOINT, UUID.randomUUID(), id); - JsonapiError error = getWithStatus(resourcePath, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); + JsonapiError error = getWithStatus(resourcePath, SC_NOT_FOUND).as(JsonapiError.class); assertErrorContainsTitle(error, String.format("Access type not found: id = %s", id)); } @Test - public void shouldReturn400OnGetByIdAndUserIfIdIsInvalid() { + void shouldReturn400OnGetByIdAndUserIfIdIsInvalid() { String id = "invalid-id"; String resourcePath = ACCESS_TYPES_PATH + "/" + id; - JsonapiError error = getWithStatus(resourcePath, SC_BAD_REQUEST, STUB_USER_ID_HEADER).as(JsonapiError.class); + JsonapiError error = getWithStatus(resourcePath, SC_BAD_REQUEST).as(JsonapiError.class); assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); } @Test - public void shouldReturn204OnDelete() { + void shouldReturn204OnDelete() { List<AccessType> accessTypes = testData(credentialsId); String accessTypeIdToDelete = insertAccessType(accessTypes.getFirst(), vertx); @@ -259,7 +211,7 @@ public void shouldReturn204OnDelete() { } @Test - public void shouldReturn400OnDeleteIfIdIsInvalid() { + void shouldReturn400OnDeleteIfIdIsInvalid() { String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPE_ID_ENDPOINT, credentialsId, "invalid-id"); JsonapiError error = deleteWithStatus(resourcePath, SC_BAD_REQUEST).as(JsonapiError.class); @@ -267,7 +219,7 @@ public void shouldReturn400OnDeleteIfIdIsInvalid() { } @Test - public void shouldReturn204OnDeleteIfNotFound() { + void shouldReturn204OnDeleteIfNotFound() { String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPE_ID_ENDPOINT, credentialsId, UUID.randomUUID()); int statusCode = deleteWithNoContent(resourcePath).response().statusCode(); @@ -275,7 +227,7 @@ public void shouldReturn204OnDeleteIfNotFound() { } @Test - public void shouldReturn204OnDeleteWhenAssignedToRecords() { + void shouldReturn204OnDeleteWhenAssignedToRecords() { List<AccessType> accessTypes = testData(credentialsId); String id = insertAccessType(accessTypes.getFirst(), vertx); insertAccessTypeMapping("11111111-1111", RecordType.PACKAGE, id, vertx); @@ -287,11 +239,11 @@ public void shouldReturn204OnDeleteWhenAssignedToRecords() { } @Test - public void shouldReturnAccessTypeWhenDataIsValid() { + void shouldReturnAccessTypeWhenDataIsValid() { String postBody = Json.encode(new AccessTypePostRequest().withData(stubbedAccessType())); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - AccessType actual = postWithStatus(resourcePath, postBody, SC_CREATED, USER8_TOKEN, USER8_ID).as(AccessType.class); + AccessType actual = postWithStatus(resourcePath, postBody, SC_CREATED).as(AccessType.class); assertNotNull(actual.getId()); assertNotNull(actual.getAttributes()); @@ -304,17 +256,17 @@ public void shouldReturnAccessTypeWhenDataIsValid() { } @Test - public void shouldReturn400WhenReachedMaximumAccessTypesSize() { + void shouldReturn400WhenReachedMaximumAccessTypesSize() { List<AccessType> accessTypes = testData(credentialsId); insertAccessType(accessTypes.get(0), vertx); insertAccessType(accessTypes.get(1), vertx); - AccessType accessType = stubbedAccessType(); + var accessType = stubbedAccessType(); accessType.getAttributes().setName(STUB_ACCESS_TYPE_NAME_3); - String postBody = Json.encode(new AccessTypePostRequest().withData(accessType)); + var postBody = Json.encode(new AccessTypePostRequest().withData(accessType)); - String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - JsonapiError error = postWithStatus(resourcePath, postBody, SC_BAD_REQUEST, USER8_TOKEN).as(JsonapiError.class); + var resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); + var error = postWithStatus(resourcePath, postBody, SC_BAD_REQUEST).as(JsonapiError.class); assertErrorContainsTitle(error, "Maximum number of access types allowed is 2"); List<AccessType> accessTypesInDb = getAccessTypes(vertx); @@ -322,55 +274,55 @@ public void shouldReturn400WhenReachedMaximumAccessTypesSize() { } @Test - public void shouldReturn400WhenPostAccessTypeWithDuplicateName() { + void shouldReturn400WhenPostAccessTypeWithDuplicateName() { List<AccessType> accessTypes = testData(credentialsId); insertAccessType(accessTypes.getFirst(), vertx); - AccessType accessType = stubbedAccessType(); + var accessType = stubbedAccessType(); stubbedAccessType().getAttributes().setName(accessTypes.getFirst().getAttributes().getName()); String postBody = Json.encode(new AccessTypePostRequest().withData(accessType)); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - JsonapiError error = - postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY, USER8_TOKEN, USER8_ID).as(JsonapiError.class); + var error = + postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Duplicate name"); } @Test - public void shouldReturn404WhenUserNotFound() { + void shouldReturn404WhenUserNotFound() { String postBody = Json.encode(new AccessTypePostRequest().withData(stubbedAccessType())); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - JsonapiError error = - postWithStatus(resourcePath, postBody, SC_NOT_FOUND, USER2_TOKEN, USER2_ID).as(JsonapiError.class); + var error = + postWithStatus(resourcePath, postBody, SC_NOT_FOUND, USER_NOT_FOUND_USER_ID_HEADER).as(JsonapiError.class); assertErrorContainsTitle(error, "User not found"); } @Test - public void shouldReturn422WhenRequestHasUnrecognizedField() { + void shouldReturn422WhenRequestHasUnrecognizedField() { String postBody = Json.encode(new AccessTypePostRequest().withData(stubbedAccessType())) .replaceFirst("type", "BadType"); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - String response = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY, USER8_TOKEN).asString(); - assertThat(response, containsString("Unrecognized field")); + String response = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT).asString(); + assertTrue(response.contains("Unrecognized field")); } @Test - public void shouldReturn422WhenPostHasInvalidUuid() { + void shouldReturn422WhenPostHasInvalidUuid() { AccessType accessType = stubbedAccessType(); accessType.setId("-2-"); String postBody = Json.encode(new AccessTypePostRequest().withData(accessType)); - String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - Errors errors = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY, USER8_TOKEN).as(Errors.class); + var resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); + var errors = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals("data.id", errors.getErrors().getFirst().getParameters().getFirst().getKey()); } @Test - public void shouldReturn400WhenContentTypeHeaderIsMissing() { + void shouldReturn400WhenContentTypeHeaderIsMissing() { String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); String error = RestAssured.given() .spec(givenWithUrl()) @@ -384,13 +336,13 @@ public void shouldReturn400WhenContentTypeHeaderIsMissing() { .extract() .asString(); - assertThat(error, containsString("Content-type")); + assertTrue(error.contains("Content-type")); } @Test - public void shouldReturn400WhenJsonIsInvalid() { - String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - String error = RestAssured.given() + void shouldReturn400WhenJsonIsInvalid() { + var resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); + var error = RestAssured.given() .spec(givenWithUrl()) .header(XOkapiHeaders.TENANT, STUB_TENANT) .header(XOkapiHeaders.TOKEN, STUB_TOKEN) @@ -404,11 +356,11 @@ public void shouldReturn400WhenJsonIsInvalid() { .extract() .asString(); - assertThat(error, containsString("Unrecognized token")); + assertTrue(error.contains("Unrecognized token")); } @Test - public void shouldReturn204OnPutByCredentialsAndAccessTypeId() { + void shouldReturn204OnPutByCredentialsAndAccessTypeId() { List<AccessType> accessTypes = testData(credentialsId); String id = insertAccessType(accessTypes.getFirst(), vertx); @@ -420,7 +372,7 @@ public void shouldReturn204OnPutByCredentialsAndAccessTypeId() { String putBody = Json.encode(new AccessTypePutRequest().withData(accessType)); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPE_ID_ENDPOINT, credentialsId, id); - putWithNoContent(resourcePath, putBody, USER9_TOKEN, USER9_ID); + putWithNoContent(resourcePath, putBody); AccessType actual = getAccessTypes(vertx).getFirst(); assertEquals(id, actual.getId()); @@ -431,24 +383,24 @@ public void shouldReturn204OnPutByCredentialsAndAccessTypeId() { } @Test - public void shouldReturn404OnPutByCredentialsAndAccessTypeIdWhenAccessTypeIsMissing() { + void shouldReturn404OnPutByCredentialsAndAccessTypeIdWhenAccessTypeIsMissing() { String putBody = Json.encode(new AccessTypePutRequest().withData(stubbedAccessType())); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPE_ID_ENDPOINT, credentialsId, UUID.randomUUID()); - JsonapiError error = putWithStatus(resourcePath, putBody, SC_NOT_FOUND, USER9_TOKEN).as(JsonapiError.class); + JsonapiError error = putWithStatus(resourcePath, putBody, SC_NOT_FOUND).as(JsonapiError.class); assertErrorContainsTitle(error, "not found"); } @Test - public void shouldReturn422OnPutByCredentialsAndAccessTypeIdWhenInvalidId() { + void shouldReturn422OnPutByCredentialsAndAccessTypeIdWhenInvalidId() { AccessType accessType = stubbedAccessType(); accessType.setId("invalid-id-format"); String putBody = Json.encode(new AccessTypePutRequest().withData(accessType)); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPE_ID_ENDPOINT, credentialsId, UUID.randomUUID()); - Errors errors = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, USER9_TOKEN).as(Errors.class); + Errors errors = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); - assertThat(errors.getErrors().getFirst().getParameters().getFirst().getKey(), equalTo("data.id")); + assertEquals("data.id", errors.getErrors().getFirst().getParameters().getFirst().getKey()); } private AccessType findAccessTypeWithId(AccessTypeCollection collection, String id) { diff --git a/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java new file mode 100644 index 000000000..d337a28ea --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java @@ -0,0 +1,196 @@ +package org.folio.rest.impl; + +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssignedUsersTestUtil.getAssignedUsers; +import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; +import static org.folio.util.KbCredentialsTestUtil.API_URL; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.KB_CREDENTIALS_ENDPOINT; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.randomId; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasProperty; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.vertx.core.json.Json; +import java.util.Map; +import java.util.UUID; +import lombok.SneakyThrows; +import org.folio.rest.jaxrs.model.AssignedUserCollection; +import org.folio.rest.jaxrs.model.AssignedUserId; +import org.folio.rest.jaxrs.model.AssignedUserPostRequest; +import org.folio.rest.jaxrs.model.Errors; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.util.IntegrationTestBase; +import org.jspecify.annotations.NonNull; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class EholdingsAssignedUsersImplIntegrationTest extends IntegrationTestBase { + + private static final String ASSIGN_USER_PATH = KB_CREDENTIALS_ENDPOINT + "/%s/users"; + private static final String KB_CREDENTIALS_ASSIGNED_USER_PATH = KB_CREDENTIALS_ENDPOINT + "/%s/users/%s"; + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturn200WithCollection() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + saveAssignedUser(JOHN_ID, credentialsId, vertx); + saveAssignedUser(JANE_ID, credentialsId, vertx); + + var assignedUsers = getWithOk(assignedUserPath(credentialsId)).as(AssignedUserCollection.class); + assertEquals(2, (int) assignedUsers.getMeta().getTotalResults()); + assertEquals(2, assignedUsers.getData().size()); + } + + @Test + void shouldReturn200WithEmptyCollection() { + var assignedUsersPath = assignedUserPath(randomId()); + + var assignedUsers = getWithOk(assignedUsersPath).as(AssignedUserCollection.class); + assertEquals(0, (int) assignedUsers.getMeta().getTotalResults()); + assertEquals(0, assignedUsers.getData().size()); + } + + @Test + void shouldReturn400WhenInvalidCredentialsId() { + var assignedUsersPath = assignedUserPath("invalid-id"); + var error = getWithStatus(assignedUsersPath, SC_BAD_REQUEST).as(JsonapiError.class); + assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); + } + + @Test + @SneakyThrows + void shouldReturn201OnPostWhenAssignedUserIsValid() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var expected = stubAssignedUserId(credentialsId); + var assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); + + mockUserById(expected.getId()); + + var postBody = Json.encode(assignedUserPostRequest); + var actual = postWithCreated(assignedUserPath(credentialsId), postBody).as(AssignedUserId.class); + + assertEquals(expected, actual); + + var assignedUsersInDb = getAssignedUsers(vertx); + assertEquals(1, assignedUsersInDb.size()); + assertEquals(expected.getId(), assignedUsersInDb.getFirst().getId()); + assertEquals(expected.getCredentialsId(), assignedUsersInDb.getFirst().getAttributes().getCredentialsId()); + } + + @Test + void shouldReturn400OnPostWhenAssignedUserIsAlreadyAssigned() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + saveAssignedUser(JOHN_ID, credentialsId, vertx); + mockUserById(JOHN_ID); + + var assignedUserPostRequest = new AssignedUserPostRequest().withData(stubAssignedUserId(credentialsId)); + var postBody = Json.encode(assignedUserPostRequest); + var error = postWithStatus(assignedUserPath(credentialsId), postBody, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "The user is already assigned"); + } + + @Test + void shouldReturn404OnPostWhenAssignedUserToMissingCredentials() { + var credentialsId = randomId(); + var expected = stubAssignedUserId(credentialsId); + mockUserById(expected.getId()); + + var assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); + var postBody = Json.encode(assignedUserPostRequest); + var error = postWithStatus(assignedUserPath(credentialsId), postBody, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "not found"); + } + + @Test + void shouldReturn422OnPostWhenAssignedUserDoesNotHaveRequiredParameters() { + var credentialsId = randomId(); + var expected = new AssignedUserId(); + + var assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); + var postBody = Json.encode(assignedUserPostRequest); + var errors = postWithStatus(assignedUserPath(credentialsId), postBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); + + assertEquals(1, errors.getErrors().size()); + assertThat(errors.getErrors(), everyItem(hasProperty("message", equalTo("must not be null")))); + } + + @Test + void shouldReturn422OnPostWhenUserDoesNotExist() { + var credentialsId = randomId(); + var expected = new AssignedUserId() + .withId(UUID.randomUUID().toString()) + .withCredentialsId(credentialsId); + + mockUserNotFound(expected.getId()); + + var assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); + var postBody = Json.encode(assignedUserPostRequest); + var errors = postWithStatus(assignedUserPath(credentialsId), postBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); + + assertEquals(1, errors.getErrors().size()); + assertThat(errors.getErrors(), everyItem(hasProperty("additionalProperties", + equalTo(Map.of("title", "Unable to assign user", "detail", "User doesn't exist"))))); + } + + @Test + void shouldReturn204OnDeleteUserAssignment() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + saveAssignedUser(JOHN_ID, credentialsId, vertx); + saveAssignedUser(JANE_ID, credentialsId, vertx); + + deleteWithNoContent(assignedUserByIdPath(credentialsId, JOHN_ID)); + + var assignedUsers = getWithOk(assignedUserPath(credentialsId)).as(AssignedUserCollection.class); + assertEquals(2, (int) assignedUsers.getMeta().getTotalResults()); + assertEquals(2, assignedUsers.getData().size()); + } + + @Test + void shouldReturn400OnDeleteWhenInvalidUserId() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var error = deleteWithStatus(assignedUserByIdPath(credentialsId, "invalid-id"), SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); + } + + @Test + void shouldReturn404OnDeleteWhenUserNotFound() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var error = deleteWithStatus(assignedUserByIdPath(credentialsId, randomId()), SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Assigned User not found by id"); + } + + private @NonNull String assignedUserByIdPath(String credentialsId, String userId) { + return String.format(KB_CREDENTIALS_ASSIGNED_USER_PATH, credentialsId, userId); + } + + private @NonNull String assignedUserPath(String credentialsId) { + return String.format(ASSIGN_USER_PATH, credentialsId); + } + + private AssignedUserId stubAssignedUserId(String credentialsId) { + return new AssignedUserId() + .withId(JOHN_ID) + .withCredentialsId(credentialsId); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java new file mode 100644 index 000000000..245b2ee6c --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java @@ -0,0 +1,694 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.holdings.HoldingsTableConstants.HOLDINGS_TABLE; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.repository.uc.UcCredentialsTableConstants.UC_CREDENTIALS_TABLE_NAME; +import static org.folio.repository.uc.UcSettingsTableConstants.UC_SETTINGS_TABLE_NAME; +import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.HoldingsTestUtil.saveHolding; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.folio.util.UcCredentialsTestUtil.setUpUcCredentials; +import static org.folio.util.UcSettingsTestUtil.saveUcSettings; +import static org.folio.util.UcSettingsTestUtil.stubSettings; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.time.OffsetDateTime; +import org.folio.repository.holdings.DbHoldingInfo; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.rest.jaxrs.model.PackageCostPerUse; +import org.folio.rest.jaxrs.model.ResourceCostPerUse; +import org.folio.rest.jaxrs.model.ResourceCostPerUseCollection; +import org.folio.rest.jaxrs.model.TitleCostPerUse; +import org.folio.util.IntegrationTestBase; +import org.jeasy.random.EasyRandom; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class EholdingsCostperuseImplIntegrationTest extends IntegrationTestBase { + + // RM API responses + private static final String GET_TITLE_WITH_COVERAGE_DATES_ASC = + "responses/rmapi/titles/get-custom-title-with-coverage-dates-asc.json"; + private static final String GET_TITLE_WITH_MANAGED_EMBARGO = + "responses/rmapi/titles/get-custom-title-with-managed-embargo.json"; + private static final String GET_TITLE_WITH_NO_SELECTED_RESOURCES = + "responses/rmapi/titles/get-custom-title-with-no-selected-resources.json"; + + // UC responses + private static final String UC_TITLE_COST_PER_USE = + "responses/uc/titles/get-title-cost-per-use-response.json"; + private static final String UC_EMPTY_TITLE_COST_PER_USE = + "responses/uc/titles/get-empty-title-cost-per-use-response.json"; + private static final String UC_TITLE_COST_PER_USE_WITH_EMPTY_NON_PUBLISHER = + "responses/uc/titles/get-title-cost-per-use-response-with-empty-non-publisher.json"; + private static final String UC_PACKAGE_COST_PER_USE = + "responses/uc/packages/get-package-cost-per-use-response.json"; + private static final String UC_PACKAGE_COST_PER_USE_EMPTY_COST = + "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; + private static final String UC_TITLE_PACKAGES_COST_PER_USE = + "responses/uc/title-packages/get-title-packages-cost-per-use-response.json"; + private static final String UC_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE = + "responses/uc/title-packages/get-title-packages-cost-per-use-for-package-response.json"; + private static final String UC_MULTIPLY_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE = + "responses/uc/title-packages/get-multiply-title-packages-cost-per-use-for-package-response.json"; + private static final String UC_DIFFERENT_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE = + "responses/uc/title-packages/get-different-title-packages-cost-per-use-for-package-response.json"; + + // KB-EBSCO expected responses + private static final String EXPECTED_RESOURCE_COST_PER_USE = + "responses/kb-ebsco/costperuse/resources/expected-resource-cost-per-use.json"; + private static final String EXPECTED_EMPTY_RESOURCE_COST_PER_USE = + "responses/kb-ebsco/costperuse/resources/expected-empty-resource-cost-per-use.json"; + private static final String EXPECTED_RESOURCE_COST_PER_USE_WITH_EMPTY_NON_PUBLISHER = + "responses/kb-ebsco/costperuse/resources/expected-resource-cost-per-use-with-empty-non-publisher.json"; + private static final String EXPECTED_TITLE_COST_PER_USE = + "responses/kb-ebsco/costperuse/titles/expected-title-cost-per-use.json"; + private static final String EXPECTED_TITLE_COST_PER_USE_WITH_NO_USAGE = + "responses/kb-ebsco/costperuse/titles/expected-title-cost-per-use-with-no-usage.json"; + private static final String EXPECTED_EMPTY_TITLE_COST_PER_USE = + "responses/kb-ebsco/costperuse/titles/expected-empty-title-cost-per-use.json"; + private static final String EXPECTED_PACKAGE_COST_PER_USE = + "responses/kb-ebsco/costperuse/packages/expected-package-cost-per-use.json"; + private static final String EXPECTED_PACKAGE_COST_PER_USE_WHEN_COST_IS_EMPTY = + "responses/kb-ebsco/costperuse/packages/expected-package-cost-per-use-when-cost-is-empty.json"; + + private final EasyRandom random = new EasyRandom(); + + private String credentialsId; + + @BeforeEach + void setUp() { + credentialsId = setupDefaultKbConfiguration(getWiremockUrl(), vertx); + saveUcSettings(stubSettings(credentialsId), vertx); + setUpUcCredentials(vertx); + mockAuthToken(); + } + + @AfterEach + void after() { + clearDataFromTable(vertx, UC_CREDENTIALS_TABLE_NAME); + clearDataFromTable(vertx, UC_SETTINGS_TABLE_NAME); + clearDataFromTable(vertx, HOLDINGS_TABLE); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnResourceCostPerUse() { + int titleId = 356; + int packageId = 473; + String year = "2019"; + String platform = "all"; + mockSuccessfulTitleCostPerUse(titleId, packageId, UC_TITLE_COST_PER_USE); + + var expected = readJsonFile(EXPECTED_RESOURCE_COST_PER_USE, ResourceCostPerUse.class); + var actual = getWithOk(resourceEndpoint(titleId, packageId, year, platform)) + .as(ResourceCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturnEmptyResourceCostPerUse() { + int titleId = 356; + int packageId = 473; + String year = "2019"; + mockSuccessfulTitleCostPerUse(titleId, packageId, UC_EMPTY_TITLE_COST_PER_USE); + + var expected = readJsonFile(EXPECTED_EMPTY_RESOURCE_COST_PER_USE, ResourceCostPerUse.class); + var actual = getWithOk(resourceEndpoint(titleId, packageId, year, null)) + .as(ResourceCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturnResourceCostPerUseWithEmptyNonPublisher() { + int titleId = 356; + int packageId = 473; + String year = "2019"; + String platform = "all"; + mockSuccessfulTitleCostPerUse(titleId, packageId, UC_TITLE_COST_PER_USE_WITH_EMPTY_NON_PUBLISHER); + + var expected = readJsonFile(EXPECTED_RESOURCE_COST_PER_USE_WITH_EMPTY_NON_PUBLISHER, ResourceCostPerUse.class); + var actual = getWithOk(resourceEndpoint(titleId, packageId, year, platform)).as(ResourceCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturn422OnGetResourceCpuWhenYearIsNull() { + int titleId = 356; + int packageId = 473; + var error = getWithStatus(resourceEndpoint(titleId, packageId, null, null), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid fiscalYear"); + } + + @Test + void shouldReturn422OnGetResourceCpuWhenPlatformIsInvalid() { + int titleId = 356; + int packageId = 473; + String year = "2019"; + String platform = "invalid"; + var error = getWithStatus(resourceEndpoint(titleId, packageId, year, platform), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid platform"); + } + + @Test + void shouldReturn400OnGetResourceCpuWhenApigeeFails() { + int titleId = 356; + int packageId = 473; + String year = "2019"; + mockGet(matching("/uc/costperuse/title/%s/%s".formatted(titleId, packageId)), "Random error message", + SC_BAD_REQUEST); + + var error = getWithStatus(resourceEndpoint(titleId, packageId, year, null), SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsDetail(error, "Random error message"); + } + + @Test + void shouldReturnTitleCostPerUse() { + int titleId = 1111111111; + int packageId = 222222; + final String year = "2019"; + final String platform = "all"; + + mockRmApiGetTitle(titleId, GET_TITLE_WITH_COVERAGE_DATES_ASC); + mockSuccessfulTitleCostPerUse(titleId, packageId, UC_TITLE_COST_PER_USE); + mockSuccessfulTitlePackageCostPerUse(UC_TITLE_PACKAGES_COST_PER_USE); + + var expected = readJsonFile(EXPECTED_TITLE_COST_PER_USE, TitleCostPerUse.class); + var actual = getWithOk(titleEndpoint(titleId, year, platform)).as(TitleCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturnTitleCostPerUseWithManagedEmbargoPeriod() { + int titleId = 1111111111; + int packageId = 222222; + final String year = "2019"; + final String platform = "nonPublisher"; + + mockRmApiGetTitle(titleId, GET_TITLE_WITH_MANAGED_EMBARGO); + mockSuccessfulTitleCostPerUse(titleId, packageId, UC_EMPTY_TITLE_COST_PER_USE); + mockSuccessfulTitlePackageCostPerUse(UC_TITLE_PACKAGES_COST_PER_USE); + + var expected = readJsonFile(EXPECTED_TITLE_COST_PER_USE_WITH_NO_USAGE, TitleCostPerUse.class); + var actual = getWithOk(titleEndpoint(titleId, year, platform)).as(TitleCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturnEmptyTitleCostPerUseWhenNoCostPerUseDataAvailable() { + int titleId = 1111111111; + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + + mockRmApiGetTitle(titleId, GET_TITLE_WITH_COVERAGE_DATES_ASC); + mockSuccessfulTitleCostPerUse(titleId, packageId, UC_EMPTY_TITLE_COST_PER_USE); + mockSuccessfulTitlePackageCostPerUse(UC_TITLE_PACKAGES_COST_PER_USE); + + var expected = readJsonFile(EXPECTED_TITLE_COST_PER_USE_WITH_NO_USAGE, TitleCostPerUse.class); + var actual = getWithOk(titleEndpoint(titleId, year, platform)).as(TitleCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturnEmptyTitleCostPerUseWhenNoSelectedResources() { + int titleId = 1111111111; + String year = "2019"; + String platform = "all"; + + mockRmApiGetTitle(titleId, GET_TITLE_WITH_NO_SELECTED_RESOURCES); + + var expected = readJsonFile(EXPECTED_EMPTY_TITLE_COST_PER_USE, TitleCostPerUse.class); + var actual = getWithOk(titleEndpoint(titleId, year, platform)).as(TitleCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturn422OnGetTitleCpuWhenYearIsNull() { + int titleId = 356; + var error = getWithStatus(titleEndpoint(titleId, null, null), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid fiscalYear"); + } + + @Test + void shouldReturn422OnGetTitleCpuWhenPlatformIsInvalid() { + int titleId = 356; + String year = "2019"; + String platform = "invalid"; + var error = getWithStatus(titleEndpoint(titleId, year, platform), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid platform"); + } + + @Test + void shouldReturnPackageCostPerUse() { + int packageId = 222222; + String year = "2019"; + String platform = "all"; + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE); + + var expected = readJsonFile(EXPECTED_PACKAGE_COST_PER_USE, PackageCostPerUse.class); + var actual = getWithOk(packageEndpoint(packageId, year, platform)).as(PackageCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturnPackageCostPerUseWhenPackageCostIsEmpty() { + int packageId = 222222; + final String year = "2019"; + final String platform = "all"; + + var holding1 = new DbHoldingInfo(1, packageId, 1, "Ionicis tormentos accelerare!", "Sunt hydraes", "Book"); + var holding2 = new DbHoldingInfo(2, packageId, 1, "Vortex, plasmator, et lixa.", "Est germanus byssus", "Book"); + saveHolding(credentialsId, holding1, OffsetDateTime.now(), vertx); + saveHolding(credentialsId, holding2, OffsetDateTime.now(), vertx); + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var expected = readJsonFile(EXPECTED_PACKAGE_COST_PER_USE_WHEN_COST_IS_EMPTY, PackageCostPerUse.class); + var actual = getWithOk(packageEndpoint(packageId, year, platform)).as(PackageCostPerUse.class); + + assertEquals(expected, actual); + } + + @Test + void shouldReturn422OnGetPackageCpuWhenYearIsNull() { + int packageId = 222222; + var error = getWithStatus(packageEndpoint(packageId, null, null), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid fiscalYear"); + } + + @Test + void shouldReturn422OnGetPackageCpuWhenPlatformIsInvalid() { + int packageId = 222222; + String year = "2019"; + String platform = "invalid"; + var error = getWithStatus(packageEndpoint(packageId, year, platform), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid platform"); + } + + @Test + void shouldReturn400OnGetPackageCpuWhenApigeeFails() { + int packageId = 222222; + String year = "2019"; + mockGet(matching("/uc/costperuse/package/%s".formatted(packageId)), "Random error message", SC_BAD_REQUEST); + + var error = getWithStatus(packageEndpoint(packageId, year, null), SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsDetail(error, "Random error message"); + } + + @Test + void shouldReturnResourcesCostPerUseCollection() { + int packageId = 222222; + final String year = "2019"; + final String platform = "all"; + + for (int i = 1; i <= 20; i++) { + saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_MULTIPLY_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(20, actual.getMeta().getTotalResults()); + assertEquals(20, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().getFirst().getAttributes(), hasProperty("usage", equalTo(2))); + assertThat(actual.getData().getFirst().getAttributes(), hasProperty("percent", equalTo(2.0 / 36 * 100))); + } + + @Test + void shouldReturnResourcesCostPerUseCollectionWithPagination() { + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + final var page = "2"; + final var size = "15"; + + for (int i = 1; i <= 20; i++) { + saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_MULTIPLY_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = + getWithOk(packageResourcesEndpoint(packageId, year, platform, page, size)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(20, actual.getMeta().getTotalResults()); + assertEquals(5, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().getFirst().getAttributes(), hasProperty("usage", equalTo(1))); + } + + @Test + void shouldReturnResourcesCostPerUseCollectionWithSortByUsageAsc() { + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + final String sort = "usage"; + final String order = "asc"; + + for (int i = 1; i <= 3; i++) { + saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_DIFFERENT_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = + getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, order)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(3, actual.getMeta().getTotalResults()); + assertEquals(3, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().get(0).getAttributes(), hasProperty("usage", equalTo(1))); + assertThat(actual.getData().get(2).getAttributes(), hasProperty("usage", equalTo(10))); + } + + @Test + void shouldReturnResourcesCostPerUseCollectionWithSortByUsageDesc() { + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + final String sort = "usage"; + final String order = "desc"; + + for (int i = 1; i <= 3; i++) { + saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_DIFFERENT_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = + getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, order)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(3, actual.getMeta().getTotalResults()); + assertEquals(3, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().get(0).getAttributes(), hasProperty("usage", equalTo(10))); + assertThat(actual.getData().get(2).getAttributes(), hasProperty("usage", equalTo(1))); + } + + @Test + void shouldReturnResourcesCostPerUseCollectionWithSortByCost() { + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + final String sort = "cost"; + + for (int i = 1; i <= 3; i++) { + saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_DIFFERENT_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = + getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(3, actual.getMeta().getTotalResults()); + assertEquals(3, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().get(0).getAttributes(), hasProperty("cost", nullValue())); + assertThat(actual.getData().get(2).getAttributes(), hasProperty("cost", equalTo(200.0))); + } + + @Test + void shouldReturnResourcesCostPerUseCollectionWithSortByCostPerUse() { + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + final String sort = "costperuse"; + + for (int i = 1; i <= 3; i++) { + saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_DIFFERENT_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = + getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(3, actual.getMeta().getTotalResults()); + assertEquals(3, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().get(0).getAttributes(), hasProperty("costPerUse", nullValue())); + assertThat(actual.getData().get(2).getAttributes(), hasProperty("costPerUse", equalTo(50.0))); + } + + @Test + void shouldReturnResourcesCostPerUseCollectionWithSortByPercent() { + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + final String sort = "percent"; + + for (int i = 1; i <= 3; i++) { + saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_DIFFERENT_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = + getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(3, actual.getMeta().getTotalResults()); + assertEquals(3, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().get(0).getAttributes(), hasProperty("percent", equalTo(1.0 / 26 * 100))); + assertThat(actual.getData().get(2).getAttributes(), hasProperty("percent", equalTo(10.0 / 26 * 100))); + } + + @Test + void shouldReturnResourcesCostPerUseCollectionSortedByNameWhenSortingByEqualsValues() { + int packageId = 222222; + final String year = "2019"; + final String platform = "publisher"; + final String sort = "type"; + + for (int i = 1; i <= 3; i++) { + saveHolding(credentialsId, generateHolding(packageId, i, String.valueOf(i)), OffsetDateTime.now(), vertx); + } + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockSuccessfulTitlePackageCostPerUse(UC_DIFFERENT_TITLE_PACKAGES_COST_PER_USE_FOR_PACKAGE); + + var actual = + getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null)) + .as(ResourceCostPerUseCollection.class); + + assertNotNull(actual); + assertEquals(3, actual.getMeta().getTotalResults()); + assertEquals(3, actual.getData().size()); + assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); + assertThat(actual.getData().get(0).getAttributes(), hasProperty("name", equalTo("1"))); + assertThat(actual.getData().get(2).getAttributes(), hasProperty("name", equalTo("3"))); + } + + @Test + void shouldReturn422OnGetPackageResourcesCpuWhenYearIsNull() { + int packageId = 222222; + var error = + getWithStatus(packageResourcesEndpoint(packageId, null, null, null, null), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid fiscalYear"); + } + + @Test + void shouldReturn422OnGetPackageResourcesCpuWhenPlatformIsInvalid() { + int packageId = 222222; + String year = "2019"; + String platform = "invalid"; + var error = + getWithStatus(packageResourcesEndpoint(packageId, year, platform, null, null), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid platform"); + } + + @Test + void shouldReturn422OnGetPackageResourcesCpuWhenSortIsInvalid() { + int packageId = 222222; + String year = "2019"; + String platform = "all"; + String sort = "invalid"; + var error = + getWithStatus(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null), + SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid sort"); + } + + @Test + void shouldReturn400OnGetPackageResourcesCpuWhenApigeeFails() { + final int packageId = 222222; + final String year = "2019"; + + saveHolding(credentialsId, generateHolding(packageId, 1), OffsetDateTime.now(), vertx); + + mockSuccessfulPackageCostPerUse(packageId, UC_PACKAGE_COST_PER_USE_EMPTY_COST); + mockPost(matching("/uc/costperuse/titles"), "Random error message", SC_BAD_REQUEST); + + var error = + getWithStatus(packageResourcesEndpoint(packageId, year, null, null, null), SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsDetail(error, "Random error message"); + } + + private void mockRmApiGetTitle(int titleId, String stubRmapiResponseFile) { + mockGet(matching(titlesRmApi(titleId)), readFile(stubRmapiResponseFile)); + } + + private void mockSuccessfulTitleCostPerUse(int titleId, int packageId, String filePath) { + mockGet(matching("/uc/costperuse/title/%s/%s".formatted(titleId, packageId)), readFile(filePath)); + } + + private void mockSuccessfulPackageCostPerUse(int packageId, String filePath) { + mockGet(matching("/uc/costperuse/package/%s".formatted(packageId)), readFile(filePath)); + } + + private void mockSuccessfulTitlePackageCostPerUse(String filePath) { + mockPost(matching("/uc/costperuse/titles"), readFile(filePath), SC_OK); + } + + private String resourceEndpoint(int titleId, int packageId, String year, String platform) { + var baseUrl = "eholdings/resources/1-%s-%s/costperuse".formatted(packageId, titleId); + var paramsSb = getEndpointParams(year, platform); + return !paramsSb.isEmpty() ? baseUrl + "?" + paramsSb : baseUrl; + } + + private String titleEndpoint(int titleId, String year, String platform) { + var baseUrl = "eholdings/titles/%s/costperuse".formatted(titleId); + var paramsSb = getEndpointParams(year, platform); + return !paramsSb.isEmpty() ? baseUrl + "?" + paramsSb : baseUrl; + } + + private String packageEndpoint(int packageId, String year, String platform) { + var baseUrl = "eholdings/packages/1-%s/costperuse".formatted(packageId); + var paramsSb = getEndpointParams(year, platform); + return !paramsSb.isEmpty() ? baseUrl + "?" + paramsSb : baseUrl; + } + + private String packageResourcesEndpoint(int packageId, String year, String platform, String page, String size) { + return packageResourcesEndpoint(packageId, year, platform, page, size, null, null); + } + + private String packageResourcesEndpoint(int packageId, String year, String platform, String page, String size, + String sort, String order) { + var baseUrl = "eholdings/packages/1-%s/resources/costperuse".formatted(packageId); + var paramsSb = getEndpointParams(year, platform, page, size, sort, order); + return !paramsSb.isEmpty() ? baseUrl + "?" + paramsSb : baseUrl; + } + + private StringBuilder getEndpointParams(String year, String platform) { + return getEndpointParams(year, platform, null, null, null, null); + } + + private StringBuilder getEndpointParams(String year, String platform, String page, String size, String sort, + String order) { + var paramsSb = new StringBuilder(); + if (year != null) { + paramsSb.append("fiscalYear=").append(year); + } + addParam(platform, paramsSb, "platform="); + addParam(page, paramsSb, "page="); + addParam(size, paramsSb, "count="); + addParam(sort, paramsSb, "sort="); + addParam(order, paramsSb, "order="); + return paramsSb; + } + + private void addParam(String value, StringBuilder paramsSb, String key) { + if (value != null) { + if (!paramsSb.isEmpty()) { + paramsSb.append("&"); + } + paramsSb.append(key).append(value); + } + } + + private DbHoldingInfo generateHolding(int packageId, int titleId) { + return DbHoldingInfo.builder() + .packageId(packageId) + .titleId(titleId) + .publicationTitle(random.nextObject(String.class)) + .publisherName(random.nextObject(String.class)) + .resourceType("Book") + .vendorId(1) + .build(); + } + + private DbHoldingInfo generateHolding(int packageId, int titleId, String titleName) { + return DbHoldingInfo.builder() + .packageId(packageId) + .titleId(titleId) + .publicationTitle(titleName) + .publisherName(random.nextObject(String.class)) + .resourceType("Book") + .vendorId(1) + .build(); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java new file mode 100644 index 000000000..9235eedc7 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java @@ -0,0 +1,41 @@ +package org.folio.rest.impl; + +import static org.folio.HttpStatus.SC_OK; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasProperty; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.folio.rest.jaxrs.model.Currency; +import org.folio.rest.jaxrs.model.CurrencyCollection; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.Test; + +class EholdingsCurrenciesImplIntegrationTest extends IntegrationTestBase { + + private static final String CURRENCIES_ENDPOINT = "/eholdings/currencies"; + + @Test + void shouldReturnAccessTypeCollectionOnGet() { + var actual = getWithStatus(CURRENCIES_ENDPOINT, SC_OK).as(CurrencyCollection.class); + + assertTrue(actual.getMeta().getTotalResults() > 0); + assertEquals(actual.getData().size(), actual.getMeta().getTotalResults()); + assertNotNull(actual.getData().getFirst()); + assertThat(actual.getData().getFirst(), + allOf( + hasProperty("id", equalTo("AFN")), + hasProperty("type", equalTo(Currency.Type.CURRENCIES)) + ) + ); + assertThat(actual.getData().getFirst().getAttributes(), + allOf( + hasProperty("code", equalTo("AFN")), + hasProperty("description", equalTo("Afghan Afghani")) + ) + ); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java new file mode 100644 index 000000000..b06cbfd80 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java @@ -0,0 +1,183 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static org.folio.HttpStatus.SC_FORBIDDEN; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssertTestUtil.assertJsonEqual; +import static org.folio.util.KbCredentialsTestUtil.KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.github.tomakehurst.wiremock.matching.RegexPattern; +import java.util.UUID; +import org.folio.rest.jaxrs.model.CustomLabelsCollection; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class EholdingsCustomLabelsImplIntegrationTest extends IntegrationTestBase { + + private static final String KB_CUSTOM_LABELS_PATH = "eholdings/custom-labels"; + + // RM API responses + private static final String RM_GET_LABELS_RESPONSE = "responses/rmapi/proxiescustomlabels/get-success-response.json"; + private static final String RM_PUT_ONE_LABEL_REQUEST = "requests/rmapi/proxiescustomlabels/put-one-label.json"; + private static final String RM_PUT_FIVE_LABEL_REQUEST = "requests/rmapi/proxiescustomlabels/put-five-labels.json"; + + // KB-EBSCO expected responses + private static final String KB_GET_CUSTOM_LABELS_RESPONSE = + "responses/kb-ebsco/custom-labels/get-custom-labels-list.json"; + + // Request payloads + private static final String REQUESTS_PATH = "requests/kb-ebsco/custom-labels"; + private static final String PUT_ONE_LABEL_REQUEST = REQUESTS_PATH + "/put-one-custom-label.json"; + private static final String PUT_FIVE_LABEL_REQUEST = REQUESTS_PATH + "/put-five-custom-labels.json"; + private static final String PUT_WITH_INVALID_ID_REQUEST = REQUESTS_PATH + "/put-custom-label-invalid-id.json"; + private static final String PUT_WITH_INVALID_NAME_REQUEST = REQUESTS_PATH + "/put-custom-label-invalid-name.json"; + private static final String PUT_WITH_DUPLICATE_ID_REQUEST = REQUESTS_PATH + "/put-custom-labels-duplicate-id.json"; + + private String credentialsId; + + @BeforeEach + void setUp() { + credentialsId = setupDefaultKbConfiguration(getWiremockUrl(), vertx); + } + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnCustomLabelsOnGet() { + mockCustomLabelsConfiguration(); + + var actual = getWithOk(KB_CUSTOM_LABELS_PATH).asString(); + assertJsonEqual(readFile(KB_GET_CUSTOM_LABELS_RESPONSE), actual, false); + verifyGet(equalTo(rootProxyCustomLabelsRmApi()), 1); + } + + @Test + void shouldReturn403OnGetWithResourcesWhenRmApi401() { + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_UNAUTHORIZED); + + var error = getWithStatus(KB_CUSTOM_LABELS_PATH, SC_FORBIDDEN).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturn403OnGetWithResourcesWhenRmApi403() { + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_FORBIDDEN); + + var error = getWithStatus(KB_CUSTOM_LABELS_PATH, SC_FORBIDDEN).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturnCustomLabelsOnGetByCredentials() { + var expected = readJsonFile(KB_GET_CUSTOM_LABELS_RESPONSE, CustomLabelsCollection.class); + expected.getData().forEach(customLabel -> customLabel.setCredentialsId(credentialsId)); + + mockCustomLabelsConfiguration(); + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, credentialsId); + var actual = getWithOk(resourcePath).as(CustomLabelsCollection.class); + + verifyGet(equalTo(rootProxyCustomLabelsRmApi()), 1); + assertEquals(expected, actual); + } + + @Test + void shouldReturn403OnGetByCredentialsWithResourcesWhenRmApi403() { + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_FORBIDDEN); + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, credentialsId); + var error = getWithStatus(resourcePath, SC_FORBIDDEN).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturn404OnGetByCredentialsWhenCredentialsAreMissing() { + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); + var error = getWithStatus(resourcePath, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KbCredentials not found by id"); + } + + @Test + void shouldUpdateCustomLabelsOnPutWhenAllIsValidWithOneItem() { + mockCustomLabelsSuccessPutRequest(); + + var putBody = readFile(PUT_ONE_LABEL_REQUEST); + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, credentialsId); + var actual = putWithOk(resourcePath, putBody).asString(); + + assertJsonEqual(readFile(PUT_ONE_LABEL_REQUEST), actual, false); + verifyPut(equalTo(rootProxyCustomLabelsRmApi()), equalToJson(readFile(RM_PUT_ONE_LABEL_REQUEST))); + } + + @Test + void shouldUpdateCustomLabelsOnPutWhenAllIsValidWithFiveItems() { + mockCustomLabelsSuccessPutRequest(); + + var putBody = readFile(PUT_FIVE_LABEL_REQUEST); + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, credentialsId); + var actual = putWithOk(resourcePath, putBody).asString(); + + assertJsonEqual(readFile(PUT_FIVE_LABEL_REQUEST), actual, false); + verifyPut(equalTo(rootProxyCustomLabelsRmApi()), equalToJson(readFile(RM_PUT_FIVE_LABEL_REQUEST))); + } + + @Test + void shouldReturn422OnPutWhenIdNotInRange() { + var putBody = readFile(PUT_WITH_INVALID_ID_REQUEST); + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid Custom Label id"); + assertErrorContainsDetail(error, "Custom Label id should be in range 1 - 5"); + } + + @Test + void shouldReturn422OnPutWhenInvalidNameLength() { + var putBody = readFile(PUT_WITH_INVALID_NAME_REQUEST); + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid Custom Label Name"); + assertErrorContainsDetail(error, "Custom Label Name is too long (maximum is 50 characters)"); + } + + @Test + void shouldReturn422OnPutWhenHasDuplicateIds() { + var putBody = readFile(PUT_WITH_DUPLICATE_ID_REQUEST); + var resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid request body"); + assertErrorContainsDetail(error, "Each label in body must contain unique id"); + } + + private void mockCustomLabelsConfiguration() { + mockGet(equalTo(rootProxyCustomLabelsRmApi()), readFile(RM_GET_LABELS_RESPONSE)); + } + + private void mockCustomLabelsSuccessPutRequest() { + mockCustomLabelsConfiguration(); + mockPut(equalTo(rootProxyCustomLabelsRmApi()), SC_NO_CONTENT); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java new file mode 100644 index 000000000..8bff0a0e7 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java @@ -0,0 +1,198 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.repository.uc.UcSettingsTableConstants.UC_SETTINGS_TABLE_NAME; +import static org.folio.util.HoldingsTestUtil.saveHoldingsFromFiles; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.UcCredentialsTestUtil.setUpUcCredentials; +import static org.folio.util.UcSettingsTestUtil.saveUcSettings; +import static org.folio.util.UcSettingsTestUtil.stubSettings; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import io.restassured.http.Header; +import org.folio.HttpHeaders; +import org.folio.util.IntegrationTestBase; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class EholdingsExportImplIntegrationTest extends IntegrationTestBase { + + // UC API endpoints + private static final String UC_COSTPERUSE_PACKAGE_REQ = "/uc/costperuse/package/%s"; + private static final String UC_COSTPERUSE_TITLES_REQ = "/uc/costperuse/titles"; + private static final String EXPORT_PACKAGE_TITLES = "/eholdings/packages/%d-%d/resources/costperuse/export%s"; + + private static final int STUB_PROVIDER_ID = 123; + private static final int STUB_PACKAGE_ID = 456; + private static final String STUB_QUERY_PARAMS = "?platform=publisher&fiscalYear=2019"; + + // UC API stub responses + private static final String UC_PACKAGE_COST_EMPTY_RESPONSE = + "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; + private static final String UC_PACKAGE_EMPTY_RESPONSE = + "responses/uc/packages/empty-package-cost-per-use-response.json"; + private static final String UC_TITLES_DIFFERENT_PACKAGES_RESPONSE = + "responses/export/get-different-title-packages-response.json"; + private static final String UC_TITLES_EMPTY_COST_RESPONSE = + "responses/export/get-empty-cost-per-use-title-response.json"; + + // Expected export responses + private static final String EXPECTED_EXPORT_THREE_ITEMS_USD = + "responses/kb-ebsco/export/expected-export-three-items-usd.txt"; + private static final String EXPECTED_EXPORT_THREE_ITEMS_ZERO_VALUES = + "responses/kb-ebsco/export/expected-export-three-items-zero-values.txt"; + private static final String EXPECTED_EMPTY_EXPORT = + "responses/kb-ebsco/export/expected-empty-export-response.txt"; + + // Holdings files + private static final String HOLDING_FOR_EXPORT_1 = "responses/kb-ebsco/export/holding-for-export-1.json"; + private static final String HOLDING_FOR_EXPORT_2 = "responses/kb-ebsco/export/holding-for-export-2.json"; + private static final String HOLDING_FOR_EXPORT_3 = "responses/kb-ebsco/export/holding-for-export-3.json"; + + private static final Header CONTENT_TYPE_CSV_HEADER = new Header(HttpHeaders.CONTENT_TYPE, "text/csv"); + + private String credentialsId; + + @BeforeEach + void setUp() { + credentialsId = setupDefaultKbConfiguration(getWiremockUrl(), vertx); + } + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, UC_SETTINGS_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnExportResponse() { + setUpUcCredentials(vertx); + saveUcSettings(stubSettings(credentialsId), vertx); + mockAuthToken(); + + saveHoldingsFromFiles(credentialsId, vertx, HOLDING_FOR_EXPORT_1, HOLDING_FOR_EXPORT_2, HOLDING_FOR_EXPORT_3); + mockFailedLocaleResponse(); + + mockGet(matching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID)), + readFile(UC_PACKAGE_COST_EMPTY_RESPONSE)); + mockPost(matching(UC_COSTPERUSE_TITLES_REQ), readFile(UC_TITLES_DIFFERENT_PACKAGES_RESPONSE), SC_OK); + + var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); + var actual = getWithOk(url, CONTENT_TYPE_CSV_HEADER).body().asString(); + + assertNotNull(actual); + assertEquals(readFile(EXPECTED_EXPORT_THREE_ITEMS_USD), actual); + } + + @Test + void shouldReturnExportWithZeroValuesResponseWhenNoCostPerUseInfo() { + setUpUcCredentials(vertx); + saveUcSettings(stubSettings(credentialsId), vertx); + mockAuthToken(); + + saveHoldingsFromFiles(credentialsId, vertx, HOLDING_FOR_EXPORT_1, HOLDING_FOR_EXPORT_2, HOLDING_FOR_EXPORT_3); + mockSuccessfulLocaleResponse(); + + mockGet(matching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID)), readFile(UC_PACKAGE_EMPTY_RESPONSE)); + mockPost(matching(UC_COSTPERUSE_TITLES_REQ), readFile(UC_TITLES_EMPTY_COST_RESPONSE), SC_OK); + + var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); + var actual = getWithOk(url, CONTENT_TYPE_CSV_HEADER).body().asString(); + + assertNotNull(actual); + assertEquals(actual, readFile(EXPECTED_EXPORT_THREE_ITEMS_ZERO_VALUES)); + } + + @Test + void shouldReturnEmptyResponseWhenNoHoldings() { + setUpUcCredentials(vertx); + saveUcSettings(stubSettings(credentialsId), vertx); + mockAuthToken(); + + mockSuccessfulLocaleResponse(); + + mockGet(matching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID)), readFile(UC_PACKAGE_EMPTY_RESPONSE)); + + var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); + var actual = getWithOk(url, CONTENT_TYPE_CSV_HEADER).body().asString(); + + var ucPackagePublisher = String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID) + + "?fiscalYear=2019&fiscalMonth=apr&analysisCurrency=USD&aggregatedFullText=true"; + + wm.verify(1, getRequestedFor(urlEqualTo(ucPackagePublisher))); + wm.verify(0, getRequestedFor(urlMatching(UC_COSTPERUSE_TITLES_REQ + "?"))); + assertEquals(actual, readFile(EXPECTED_EMPTY_EXPORT)); + } + + @Test + void shouldReturnResponseWithPublisherEqualsToAllWhenNotSpecifiedInUrl() { + setUpUcCredentials(vertx); + saveUcSettings(stubSettings(credentialsId), vertx); + mockAuthToken(); + + saveHoldingsFromFiles(credentialsId, vertx, HOLDING_FOR_EXPORT_1, HOLDING_FOR_EXPORT_2, HOLDING_FOR_EXPORT_3); + mockFailedLocaleResponse(); + + var requestUrl = String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID); + mockGet(matching(requestUrl), readFile(UC_PACKAGE_COST_EMPTY_RESPONSE)); + mockPost(matching(UC_COSTPERUSE_TITLES_REQ), readFile(UC_TITLES_DIFFERENT_PACKAGES_RESPONSE), SC_OK); + + var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, "?fiscalYear=2019"); + var actual = getWithOk(url, CONTENT_TYPE_CSV_HEADER).body().asString(); + + assertNotNull(actual); + wm.verify(1, getRequestedFor( + urlEqualTo(requestUrl + "?fiscalYear=2019&fiscalMonth=apr&analysisCurrency=USD&aggregatedFullText=true"))); + wm.verify(1, postRequestedFor(urlEqualTo(ucCostPerUseTitlesUrl("2019", "apr", "USD", false, false)))); + wm.verify(1, postRequestedFor(urlEqualTo(ucCostPerUseTitlesUrl("2019", "apr", "USD", true, false)))); + } + + @Test + void shouldReturn401ErrorWhenCanNotRetrieveAuthToken() { + setUpUcCredentials(vertx); + saveUcSettings(stubSettings(credentialsId), vertx); + + mockPost(matching("/oauth-proxy/token"), "Unable to proceed request", SC_BAD_REQUEST); + mockSuccessfulLocaleResponse(); + + var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); + + var error = getWithStatus(url, SC_UNAUTHORIZED, CONTENT_TYPE_CSV_HEADER).asString(); + + assertThat(error, Matchers.containsString("Unrecognized token")); + } + + @Test + void shouldReturnExportFileWithDefaultLocaleSettings() { + setUpUcCredentials(vertx); + saveUcSettings(stubSettings(credentialsId), vertx); + mockAuthToken(); + + saveHoldingsFromFiles(credentialsId, vertx, + HOLDING_FOR_EXPORT_1, HOLDING_FOR_EXPORT_2, HOLDING_FOR_EXPORT_3); + mockFailedLocaleResponse(); + + mockGet(matching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID)), readFile(UC_PACKAGE_EMPTY_RESPONSE)); + mockPost(matching(UC_COSTPERUSE_TITLES_REQ), readFile(UC_TITLES_EMPTY_COST_RESPONSE), SC_OK); + + var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); + var actual = getWithOk(url, CONTENT_TYPE_CSV_HEADER).body().asString(); + assertNotNull(actual); + + assertEquals(actual, readFile(EXPECTED_EXPORT_THREE_ITEMS_ZERO_VALUES)); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java new file mode 100644 index 000000000..6ebf82e34 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java @@ -0,0 +1,651 @@ +package org.folio.rest.impl; + +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_CREATED; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; +import static org.folio.util.HoldingsRetryStatusTestUtil.getRetryStatus; +import static org.folio.util.HoldingsStatusUtil.getStatus; +import static org.folio.util.KbCredentialsTestUtil.API_URL; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.KB_CREDENTIALS_ENDPOINT; +import static org.folio.util.KbCredentialsTestUtil.STUB_USERNAME; +import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID; +import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_OTHER_HEADER; +import static org.folio.util.KbCredentialsTestUtil.STUB_USER_OTHER_ID; +import static org.folio.util.KbCredentialsTestUtil.USER_KB_CREDENTIAL_ENDPOINT; +import static org.folio.util.KbCredentialsTestUtil.getKbCredentials; +import static org.folio.util.KbCredentialsTestUtil.getKbCredentialsNonSecured; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.KbCredentialsTestUtil.stubPatchRequest; +import static org.folio.util.KbCredentialsTestUtil.stubbedCredentials; +import static org.folio.util.PackagesTestUtil.buildDbPackage; +import static org.folio.util.PackagesTestUtil.savePackage; +import static org.folio.util.ProvidersTestUtil.buildDbProvider; +import static org.folio.util.ProvidersTestUtil.saveProvider; +import static org.folio.util.ResourcesTestUtil.buildResource; +import static org.folio.util.ResourcesTestUtil.saveResource; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TitlesTestUtil.buildTitle; +import static org.folio.util.TitlesTestUtil.saveTitle; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.vertx.core.json.Json; +import java.util.UUID; +import org.apache.commons.collections4.map.CaseInsensitiveMap; +import org.apache.commons.lang3.StringUtils; +import org.folio.okapi.common.XOkapiHeaders; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.rest.jaxrs.model.KbCredentials; +import org.folio.rest.jaxrs.model.KbCredentialsCollection; +import org.folio.rest.jaxrs.model.KbCredentialsKey; +import org.folio.rest.jaxrs.model.KbCredentialsPostRequest; +import org.folio.rest.jaxrs.model.KbCredentialsPutRequest; +import org.folio.rest.jaxrs.model.LoadStatusNameEnum; +import org.folio.service.kbcredentials.KbCredentialsService; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +class EholdingsKbCredentialsImplIntegrationTest extends IntegrationTestBase { + + private static final String STARS_256 = "*".repeat(256); + private static final String OTHER_CUST_ID = "OTHER_CUST_ID"; + + @Autowired + @Qualifier("nonSecuredCredentialsService") + private KbCredentialsService nonSecuredCredentialsService; + + @Autowired + private KbCredentialsService securedCredentialsService; + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnKbCredentialsCollectionOnGet() { + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var actual = getWithOk(KB_CREDENTIALS_ENDPOINT).as(KbCredentialsCollection.class); + + assertEquals(1, actual.getData().size()); + assertEquals(Integer.valueOf(1), actual.getMeta().getTotalResults()); + var credentials = actual.getData().getFirst(); + assertNotNull(credentials); + assertNotNull(credentials.getId()); + + assertEquals(API_URL, credentials.getAttributes().getUrl()); + assertEquals(CREDENTIALS_NAME, credentials.getAttributes().getName()); + assertEquals(STUB_CUSTOMER_ID, credentials.getAttributes().getCustomerId()); + assertEquals(StringUtils.repeat("*", 40), credentials.getAttributes().getApiKey()); + + assertEquals(STUB_USERNAME, credentials.getMeta().getCreatedByUsername()); + assertEquals(STUB_USER_ID, credentials.getMeta().getCreatedByUserId()); + assertNotNull(credentials.getMeta().getCreatedDate()); + } + + @Test + void shouldReturnEmptyKbCredentialsCollectionOnGet() { + var actual = getWithOk(KB_CREDENTIALS_ENDPOINT).as(KbCredentialsCollection.class); + + assertNotNull(actual.getData()); + assertEquals(0, actual.getData().size()); + assertEquals(Integer.valueOf(0), actual.getMeta().getTotalResults()); + } + + @Test + void shouldReturn201OnPostIfCredentialsAreValid() { + var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(stubbedCredentials(getWiremockUrl())); + var postBody = Json.encode(kbCredentialsPostRequest); + + mockVerifyValidCredentialsRequest(); + var actual = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_CREATED).as(KbCredentials.class); + + assertNotNull(actual); + assertNotNull(actual.getId()); + assertNotNull(actual.getType()); + assertEquals(getWiremockUrl(), actual.getAttributes().getUrl()); + assertEquals(CREDENTIALS_NAME, actual.getAttributes().getName()); + assertEquals(STUB_CUSTOMER_ID, actual.getAttributes().getCustomerId()); + assertEquals(STUB_USER_ID, actual.getMeta().getCreatedByUserId()); + assertNotNull(actual.getMeta().getCreatedDate()); + } + + @Test + void shouldReturn422OnPostWhenCredentialsAreInvalid() { + var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(stubbedCredentials(getWiremockUrl())); + var postBody = Json.encode(kbCredentialsPostRequest); + + mockVerifyFailedCredentialsRequest(); + var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KB API Credentials are invalid"); + } + + @Test + void shouldReturn422OnPostWhenCredentialsNameIsLongerThen255() { + var creds = stubbedCredentials(getWiremockUrl()); + creds.getAttributes().setName(STARS_256); + + var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); + var postBody = Json.encode(kbCredentialsPostRequest); + + var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + assertErrorContainsDetail(error, "name is too long (maximum is 255 characters)"); + } + + @Test + void shouldReturn422OnPostWhenCredentialsNameIsEmpty() { + var creds = stubbedCredentials(getWiremockUrl()); + creds.getAttributes().setName(""); + + var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); + var postBody = Json.encode(kbCredentialsPostRequest); + + var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + assertErrorContainsDetail(error, "name must not be empty"); + } + + @Test + void shouldReturn422OnPostWhenCredentialsWithProvidedNameAlreadyExist() { + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(stubbedCredentials(getWiremockUrl())); + var postBody = Json.encode(kbCredentialsPostRequest); + + mockVerifyValidCredentialsRequest(); + var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Duplicate name"); + assertErrorContainsDetail(error, String.format("Credentials with name '%s' already exist", CREDENTIALS_NAME)); + } + + @Test + void shouldReturn422OnPostWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() { + saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var creds = stubbedCredentials(getWiremockUrl()); + creds.getAttributes().setName("Other KB"); + + var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); + var postBody = Json.encode(kbCredentialsPostRequest); + + mockVerifyValidCredentialsRequest(); + var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Duplicate credentials"); + assertErrorContainsDetail(error, String.format("Credentials with customer id '%s' and url '%s' already exist", + STUB_CUSTOMER_ID, getWiremockUrl())); + } + + @Test + void shouldReturnKbCredentialsOnGet() { + var credentialsId = + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + var actual = getWithOk(resourcePath).as(KbCredentials.class); + + assertEquals(getKbCredentials(vertx).getFirst(), actual); + } + + @Test + void shouldReturnKbCredentialsKeyOnGet() { + var credentialsId = + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId + "/key"; + var actual = getWithOk(resourcePath).as(KbCredentialsKey.class); + + assertEquals(STUB_API_KEY, actual.getAttributes().getApiKey()); + } + + @Test + void shouldReturn400OnGetWhenIdIsInvalid() { + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; + var error = getWithStatus(resourcePath, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); + } + + @Test + void shouldReturn404OnGetWhenCredentialsAreMissing() { + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = getWithStatus(resourcePath, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KbCredentials not found by id"); + } + + @Test + void shouldReturn204OnPatchIfCredentialsAreValid() { + var credentialsId = saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setCustomerId("updated"); + + var patchBody = Json.encode(kbCredentialsPatchRequest); + + mockVerifyValidCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + patchWithNoContent(resourcePath, patchBody); + + var actual = getKbCredentialsNonSecured(vertx).getFirst(); + + assertNotNull(actual); + assertNotNull(actual.getId()); + assertNotNull(actual.getType()); + assertEquals(getWiremockUrl(), actual.getAttributes().getUrl()); + assertEquals(STUB_API_KEY, actual.getAttributes().getApiKey()); + assertEquals(CREDENTIALS_NAME, actual.getAttributes().getName()); + assertEquals("updated", actual.getAttributes().getCustomerId()); + assertEquals(STUB_USER_ID, actual.getMeta().getCreatedByUserId()); + assertNotNull(actual.getMeta().getCreatedDate()); + assertEquals(STUB_USER_ID, actual.getMeta().getUpdatedByUserId()); + assertNotNull(actual.getMeta().getUpdatedDate()); + } + + @Test + void shouldReturn422OnPatchWhenCredentialsAreInvalid() { + var credentialsId = saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setCustomerId("updated"); + + var patchBody = Json.encode(kbCredentialsPatchRequest); + + mockVerifyFailedCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KB API Credentials are invalid"); + } + + @Test + void shouldReturn422OnPatchWhenCredentialsNameIsLongerThen255() { + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setName(STARS_256); + + var patchBody = Json.encode(kbCredentialsPatchRequest); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + assertErrorContainsDetail(error, "name is too long (maximum is 255 characters)"); + } + + @Test + void shouldReturn422OnPatchWhenCredentialsNameIsEmpty() { + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setName(""); + kbCredentialsPatchRequest.getData().getAttributes().setCustomerId(STUB_CUSTOMER_ID); + + var patchBody = Json.encode(kbCredentialsPatchRequest); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + assertErrorContainsDetail(error, "name must not be empty"); + } + + @Test + void shouldReturn422OnPatchWhenAllFieldsAreEmpty() { + var kbCredentialsPatchRequest = stubPatchRequest(); + var patchBody = Json.encode(kbCredentialsPatchRequest); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid attributes"); + assertErrorContainsDetail(error, "At least one of attributes must not be empty"); + } + + @Test + void shouldReturn422OnPatchWhenCredentialsWithProvidedNameAlreadyExist() { + saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var credentialsId = saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME + "2", + STUB_API_KEY, OTHER_CUST_ID, vertx); + + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setName(CREDENTIALS_NAME); + var patchBody = Json.encode(kbCredentialsPatchRequest); + + mockVerifyValidCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Duplicate name"); + assertErrorContainsDetail(error, String.format("Credentials with name '%s' already exist", CREDENTIALS_NAME)); + } + + @Test + void shouldReturn422OnPatchWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() { + saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setCustomerId(STUB_CUSTOMER_ID); + kbCredentialsPatchRequest.getData().getAttributes().setUrl(getWiremockUrl()); + var patchBody = Json.encode(kbCredentialsPatchRequest); + + mockVerifyValidCredentialsRequest(); + var credentialsId = saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME + "2", + STUB_API_KEY, OTHER_CUST_ID, vertx); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Duplicate credentials"); + assertErrorContainsDetail(error, String.format("Credentials with customer id '%s' and url '%s' already exist", + STUB_CUSTOMER_ID, getWiremockUrl())); + } + + @Test + void shouldReturn400OnPatchWhenIdIsInvalid() { + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setName(CREDENTIALS_NAME); + + var patchBody = Json.encode(kbCredentialsPatchRequest); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; + var error = patchWithStatus(resourcePath, patchBody, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); + } + + @Test + void shouldReturn404OnPatchWhenCredentialsAreMissing() { + var kbCredentialsPatchRequest = stubPatchRequest(); + kbCredentialsPatchRequest.getData().getAttributes().setName(CREDENTIALS_NAME); + + var patchBody = Json.encode(kbCredentialsPatchRequest); + + mockVerifyValidCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = + patchWithStatus(resourcePath, patchBody, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KbCredentials not found by id"); + } + + @Test + void shouldReturn204OnPutIfCredentialsAreValid() { + var credentialsId = + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var creds = stubbedCredentials(getWiremockUrl()); + creds.getAttributes() + .withName(CREDENTIALS_NAME + "updated") + .withCustomerId(STUB_CUSTOMER_ID + "updated"); + + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); + var putBody = Json.encode(kbCredentialsPutRequest); + + mockVerifyValidCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + putWithNoContent(resourcePath, putBody); + + var actual = getKbCredentials(vertx).getFirst(); + + assertNotNull(actual); + assertNotNull(actual.getId()); + assertNotNull(actual.getType()); + assertEquals(getWiremockUrl(), actual.getAttributes().getUrl()); + assertEquals(CREDENTIALS_NAME + "updated", actual.getAttributes().getName()); + assertEquals(STUB_CUSTOMER_ID + "updated", actual.getAttributes().getCustomerId()); + assertEquals(STUB_USER_ID, actual.getMeta().getCreatedByUserId()); + assertNotNull(actual.getMeta().getCreatedDate()); + assertEquals(STUB_USER_ID, actual.getMeta().getUpdatedByUserId()); + assertNotNull(actual.getMeta().getUpdatedDate()); + } + + @Test + void shouldReturn422OnPutWhenCredentialsAreInvalid() { + var credentialsId = + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(stubbedCredentials(getWiremockUrl())); + var putBody = Json.encode(kbCredentialsPutRequest); + + mockVerifyFailedCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KB API Credentials are invalid"); + } + + @Test + void shouldReturn422OnPutWhenCredentialsNameIsLongerThen255() { + var creds = stubbedCredentials(getWiremockUrl()); + creds.getAttributes().setName(STARS_256); + + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); + var putBody = Json.encode(kbCredentialsPutRequest); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + assertErrorContainsDetail(error, "name is too long (maximum is 255 characters)"); + } + + @Test + void shouldReturn422OnPutWhenCredentialsNameIsEmpty() { + var creds = stubbedCredentials(getWiremockUrl()); + creds.getAttributes().setName(""); + + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); + var putBody = Json.encode(kbCredentialsPutRequest); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + assertErrorContainsDetail(error, "name must not be empty"); + } + + @Test + void shouldReturn422OnPutWhenCredentialsWithProvidedNameAlreadyExist() { + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME + "2", STUB_API_KEY, OTHER_CUST_ID, vertx); + + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(stubbedCredentials(getWiremockUrl())); + var putBody = Json.encode(kbCredentialsPutRequest); + + mockVerifyValidCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Duplicate name"); + assertErrorContainsDetail(error, String.format("Credentials with name '%s' already exist", CREDENTIALS_NAME)); + } + + @Test + void shouldReturn422OnPutWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() { + saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var credentialsId = saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME + "2", STUB_API_KEY, OTHER_CUST_ID, vertx); + + var creds = stubbedCredentials(getWiremockUrl()); + creds.getAttributes().setName(CREDENTIALS_NAME + "2"); + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); + var putBody = Json.encode(kbCredentialsPutRequest); + + mockVerifyValidCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Duplicate credentials"); + assertErrorContainsDetail(error, String.format("Credentials with customer id '%s' and url '%s' already exist", + STUB_CUSTOMER_ID, getWiremockUrl())); + } + + @Test + void shouldReturn400OnPutWhenIdIsInvalid() { + var creds = stubbedCredentials(getWiremockUrl()); + creds.setId(UUID.randomUUID().toString()); + + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); + var putBody = Json.encode(kbCredentialsPutRequest); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; + var error = putWithStatus(resourcePath, putBody, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); + } + + @Test + void shouldReturn404OnPutWhenCredentialsAreMissing() { + var creds = stubbedCredentials(getWiremockUrl()); + creds.setId(UUID.randomUUID().toString()); + + var kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); + var putBody = Json.encode(kbCredentialsPutRequest); + + mockVerifyValidCredentialsRequest(); + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + var error = putWithStatus(resourcePath, putBody, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KbCredentials not found by id"); + } + + @Test + void shouldReturn204OnDelete() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + deleteWithNoContent(resourcePath); + + var kbCredentialsInDb = getKbCredentials(vertx); + assertTrue(kbCredentialsInDb.isEmpty()); + } + + @Test + void shouldReturn204OnDeleteWhenHasRelatedRecords() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + saveAssignedUser(STUB_USER_ID, credentialsId, vertx); + saveProvider(buildDbProvider(STUB_VENDOR_ID, credentialsId, STUB_VENDOR_NAME), vertx); + savePackage(buildDbPackage(FULL_PACKAGE_ID, credentialsId, STUB_PACKAGE_NAME), vertx); + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, credentialsId, STUB_TITLE_NAME), vertx); + saveTitle(buildTitle(STUB_TITLE_ID, credentialsId, STUB_TITLE_NAME), vertx); + + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; + deleteWithNoContent(resourcePath); + + var kbCredentialsInDb = getKbCredentials(vertx); + assertTrue(kbCredentialsInDb.isEmpty()); + } + + @Test + void shouldReturn204OnDeleteWhenCredentialsAreMissing() { + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; + deleteWithNoContent(resourcePath); + + var kbCredentialsInDb = getKbCredentials(vertx); + assertTrue(kbCredentialsInDb.isEmpty()); + } + + @Test + void shouldReturn400OnDeleteWhenIdIsInvalid() { + var resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; + var error = deleteWithStatus(resourcePath, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); + } + + @Test + void shouldReturn200AndKbCredentialsOnGetByUser() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + saveAssignedUser(STUB_USER_ID, credentialsId, vertx); + + var actual = getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_OK).as(KbCredentials.class); + assertEquals(getKbCredentialsNonSecured(vertx).getFirst(), actual); + } + + @Test + void shouldReturn200AndKbCredentialsOnGetByUserWhenSingleKbCredentialsPresent() { + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + + var actual = getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_OK).as(KbCredentials.class); + assertEquals(getKbCredentialsNonSecured(vertx).getFirst(), actual); + } + + @Test + void shouldReturn404OnGetByUserWhenAssignedUserIsMissingAndNoKbCredentialsAtAll() { + var error = getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KB Credentials do not exist "); + } + + @Test + void shouldReturn404OnGetByUserWhenUserIsNotTheOneWhoIsAssigned() { + var credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + saveAssignedUser(STUB_USER_ID, credentialsId, vertx); + + var error = + getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_NOT_FOUND, STUB_USER_ID_OTHER_HEADER).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KB Credentials do not exist or user with userId = " + STUB_USER_OTHER_ID + + " is not assigned to any available knowledgebase."); + } + + @Test + void shouldReturnStatusNotStartedOnKbCredentialsCreation() { + var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(stubbedCredentials(getWiremockUrl())); + var postBody = Json.encode(kbCredentialsPostRequest); + + mockVerifyValidCredentialsRequest(); + var actual = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_CREATED).as(KbCredentials.class); + + var status = getStatus(actual.getId(), vertx); + assertEquals(LoadStatusNameEnum.NOT_STARTED, status.getData().getAttributes().getStatus().getName()); + + var retryStatus = getRetryStatus(actual.getId(), vertx); + assertNotNull(retryStatus); + } + + @Test + void shouldReturnSecuredCollection() { + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var headers = new CaseInsensitiveMap<String, String>(); + headers.put(XOkapiHeaders.TENANT, STUB_TENANT); + var collection = securedCredentialsService.findAll(headers).join(); + assertEquals(1, collection.getMeta().getTotalResults()); + var credentials = collection.getData().getFirst(); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, credentials.getType()); + assertEquals(CREDENTIALS_NAME, credentials.getAttributes().getName()); + assertTrue(credentials.getAttributes().getApiKey().contains("*")); + assertEquals(STUB_CUSTOMER_ID, credentials.getAttributes().getCustomerId()); + assertEquals(API_URL, credentials.getAttributes().getUrl()); + } + + @Test + void shouldReturnNonSecuredCollection() { + saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + var headers = new CaseInsensitiveMap<String, String>(); + headers.put(XOkapiHeaders.TENANT, STUB_TENANT); + var collection = nonSecuredCredentialsService.findAll(headers).join(); + assertEquals(1, collection.getMeta().getTotalResults()); + var credentials = collection.getData().getFirst(); + assertEquals(KbCredentials.Type.KB_CREDENTIALS, credentials.getType()); + assertEquals(CREDENTIALS_NAME, credentials.getAttributes().getName()); + assertEquals(STUB_API_KEY, credentials.getAttributes().getApiKey()); + assertEquals(STUB_CUSTOMER_ID, credentials.getAttributes().getCustomerId()); + assertEquals(API_URL, credentials.getAttributes().getUrl()); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java new file mode 100644 index 000000000..5afb43721 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java @@ -0,0 +1,1263 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; +import static java.lang.String.format; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_FORBIDDEN; +import static org.folio.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.RecordType.PACKAGE; +import static org.folio.repository.RecordType.RESOURCE; +import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; +import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.repository.packages.PackageTableConstants.PACKAGES_TABLE_NAME; +import static org.folio.repository.resources.ResourceTableConstants.RESOURCES_TABLE_NAME; +import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; +import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME; +import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME_2; +import static org.folio.util.AccessTypesTestUtil.getAccessTypeMappings; +import static org.folio.util.AccessTypesTestUtil.insertAccessType; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; +import static org.folio.util.AccessTypesTestUtil.testData; +import static org.folio.util.AssertTestUtil.assertEqualsPackageId; +import static org.folio.util.AssertTestUtil.assertEqualsUuid; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssertTestUtil.assertJsonEqual; +import static org.folio.util.KbCredentialsTestUtil.getDefaultKbConfiguration; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.PackagesTestUtil.buildDbPackage; +import static org.folio.util.PackagesTestUtil.savePackage; +import static org.folio.util.TagsTestUtil.saveTag; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import io.vertx.core.Vertx; +import io.vertx.core.json.Json; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Objects; +import org.folio.holdingsiq.model.CoverageDates; +import org.folio.holdingsiq.model.PackageData; +import org.folio.holdingsiq.model.PackagePut; +import org.folio.rest.jaxrs.model.ContentType; +import org.folio.rest.jaxrs.model.Errors; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.rest.jaxrs.model.KbCredentials; +import org.folio.rest.jaxrs.model.Package; +import org.folio.rest.jaxrs.model.PackageCollection; +import org.folio.rest.jaxrs.model.PackagePostRequest; +import org.folio.rest.jaxrs.model.PackagePutRequest; +import org.folio.rest.jaxrs.model.PackageTags; +import org.folio.rest.jaxrs.model.PackageTagsPutRequest; +import org.folio.rest.jaxrs.model.ResourceCollection; +import org.folio.rest.jaxrs.model.Tags; +import org.folio.util.AccessTypesTestUtil; +import org.folio.util.IntegrationTestBase; +import org.folio.util.PackagesTestUtil; +import org.folio.util.TagsTestUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class EholdingsPackagesIntegrationTest extends IntegrationTestBase { + + // RM API responses + private static final String PACKAGE_STUB_FILE = + "responses/rmapi/packages/get-package-by-id-response.json"; + private static final String PACKAGE_2_STUB_FILE = + "responses/rmapi/packages/get-package-by-id-2-response.json"; + private static final String CUSTOM_PACKAGE_STUB_FILE = + "responses/rmapi/packages/get-custom-package-by-id-response.json"; + private static final String RESOURCES_BY_PACKAGE_ID_STUB_FILE = + "responses/rmapi/resources/get-resources-by-package-id-response.json"; + private static final String RESOURCES_BY_PACKAGE_ID_EMPTY_STUB_FILE = + "responses/rmapi/resources/get-resources-by-package-id-response-empty.json"; + private static final String RESOURCES_BY_PACKAGE_ID_EMPTY_CUSTOMER_RESOURCE_LIST_STUB_FILE = + "responses/rmapi/resources/get-resources-by-package-id-response-empty-customer-list.json"; + private static final String VENDOR_BY_PACKAGE_ID_STUB_FILE = + "responses/rmapi/vendors/get-vendor-by-id-for-package.json"; + private static final String GET_PACKAGES_RESPONSE = + "responses/rmapi/packages/get-packages-response.json"; + private static final String GET_PACKAGES_BY_PROVIDER_RESPONSE = + "responses/rmapi/packages/get-packages-by-provider-id.json"; + private static final String GET_PACKAGE_PROVIDER_RESPONSE = + "responses/rmapi/packages/get-package-provider-by-id.json"; + private static final String POST_PACKAGE_CREATED_RESPONSE = + "responses/rmapi/packages/post-package-response.json"; + private static final String POST_PACKAGE_400_RESPONSE = + "responses/rmapi/packages/post-package-400-error-response.json"; + private static final String GET_PACKAGE_RESOURCES_400_RESPONSE = + "responses/rmapi/packages/get-package-resources-400-response.json"; + private static final String GET_PACKAGE_NOT_FOUND_RESPONSE = + "responses/rmapi/packages/get-package-by-id-not-found-response.json"; + private static final String GET_PROXIES_CUSTOMLABELS_RESPONSE = + "responses/rmapi/proxiescustomlabels/get-success-response.json"; + private static final String GET_TITLE_BY_ID_RESPONSE = + "responses/rmapi/titles/get-title-by-id-response.json"; + + // KB-EBSCO expected responses + private static final String EXPECTED_PACKAGE_BY_ID_STUB_FILE = + "responses/kb-ebsco/packages/expected-package-by-id.json"; + private static final String EXPECTED_RESOURCES_STUB_FILE = + "responses/kb-ebsco/resources/expected-resources-by-package-id.json"; + private static final String EXPECTED_RESOURCES_WITH_TAGS_STUB_FILE = + "responses/kb-ebsco/resources/expected-resources-by-package-id-with-tags.json"; + private static final String EXPECTED_PACKAGES_COLLECTION_5 = + "responses/kb-ebsco/packages/expected-package-collection-with-five-elements.json"; + private static final String EXPECTED_PACKAGES_COLLECTION_1 = + "responses/kb-ebsco/packages/expected-package-collection-with-one-element.json"; + private static final String EXPECTED_PACKAGE_WITH_PROVIDER = + "responses/kb-ebsco/packages/expected-package-by-id-with-provider.json"; + private static final String EXPECTED_POST_PACKAGES_BULK = + "responses/kb-ebsco/packages/expected-post-packages-bulk.json"; + private static final String EXPECTED_POST_PACKAGES_BULK_FAILED = + "responses/kb-ebsco/packages/expected-post-packages-bulk-with-failed-id.json"; + private static final String EXPECTED_POST_PACKAGES_BULK_EMPTY = + "responses/kb-ebsco/packages/expected-post-packages-bulk-empty.json"; + + // Request payloads + private static final String PUT_PACKAGE_SELECTED_REQUEST = + "requests/kb-ebsco/package/put-package-selected.json"; + private static final String PUT_PACKAGE_SELECTED_WITH_ACCESS_TYPE_REQUEST = + "requests/kb-ebsco/package/put-package-selected-with-access-type.json"; + private static final String PUT_PACKAGE_NOT_SELECTED_NON_EMPTY_REQUEST = + "requests/kb-ebsco/package/put-package-not-selected-non-empty-fields.json"; + private static final String PUT_PACKAGE_CUSTOM_MULTIPLE_ATTRIBUTES_REQUEST = + "requests/kb-ebsco/package/put-package-custom-multiple-attributes.json"; + private static final String PUT_PACKAGE_CUSTOM_WITH_ACCESS_TYPE_REQUEST = + "requests/kb-ebsco/package/put-package-custom-with-access-type.json"; + private static final String PUT_PACKAGE_WITH_NOT_EXISTED_ACCESS_TYPE_REQUEST = + "requests/kb-ebsco/package/put-package-with-not-existed-access-type.json"; + private static final String PUT_PACKAGE_WITH_INVALID_ACCESS_TYPE_REQUEST = + "requests/kb-ebsco/package/put-package-with-invalid-access-type.json"; + private static final String PUT_PACKAGE_TAGS_REQUEST = + "requests/kb-ebsco/package/put-package-tags.json"; + private static final String POST_PACKAGE_REQUEST = + "requests/kb-ebsco/package/post-package-request.json"; + private static final String POST_PACKAGE_WITH_ACCESS_TYPE_REQUEST = + "requests/kb-ebsco/package/post-package-with-access-type-request.json"; + private static final String POST_PACKAGE_WITH_NOT_EXISTED_ACCESS_TYPE_REQUEST = + "requests/kb-ebsco/package/post-package-with-not-existed-access-type-request.json"; + private static final String POST_PACKAGE_WITH_INVALID_ACCESS_TYPE_REQUEST = + "requests/kb-ebsco/package/post-package-with-invalid-access-type-request.json"; + private static final String POST_PACKAGES_BULK_REQUEST = + "requests/kb-ebsco/package/post-packages-bulk.json"; + private static final String POST_PACKAGES_BULK_WITH_INVALID_ID_REQUEST = + "requests/kb-ebsco/package/post-packages-bulk-with-invalid-id-format.json"; + private static final String POST_PACKAGES_BULK_WITH_NON_EXISTING_ID_REQUEST = + "requests/kb-ebsco/package/post-packages-bulk-with-non-existing-id.json"; + private static final String POST_PACKAGES_BULK_EMPTY_REQUEST = + "requests/kb-ebsco/package/post-packages-bulk-empty.json"; + + // RM API request payloads + private static final String PUT_PACKAGE_SELECTED_RMAPI_REQUEST = + "requests/rmapi/packages/put-package-is-selected.json"; + private static final String PUT_PACKAGE_CUSTOM_RMAPI_REQUEST = + "requests/rmapi/packages/put-package-custom.json"; + private static final String POST_PACKAGE_RMAPI_REQUEST = + "requests/rmapi/packages/post-package.json"; + + private KbCredentials configuration; + + @BeforeEach + void setUp() { + setupDefaultKbConfiguration(getWiremockUrl(), vertx); + configuration = getDefaultKbConfiguration(vertx); + } + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); + clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); + clearDataFromTable(vertx, TAGS_TABLE_NAME); + clearDataFromTable(vertx, RESOURCES_TABLE_NAME); + clearDataFromTable(vertx, PACKAGES_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnPackagesOnGet() { + mockGet(matching(packagesRmApi() + ".*"), readFile(GET_PACKAGES_RESPONSE)); + var expected = readJsonFile(EXPECTED_PACKAGES_COLLECTION_5, PackageCollection.class); + + var actual = getWithOk(packagesPath() + "?q=American&filter[type]=abstractandindex&count=5") + .as(PackageCollection.class); + assertEquals(expected, actual); + } + + @Test + void shouldReturnPackagesOnSearchByTagsOnly() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE_2); + saveTag(vertx, FULL_PACKAGE_ID_3, PACKAGE, STUB_TAG_VALUE_3); + + setUpPackages(vertx, configuration.getId()); + + var packageCollection = getWithOk(withTagFilters(packagesPath(), STUB_TAG_VALUE, STUB_TAG_VALUE_2)) + .as(PackageCollection.class); + var packages = packageCollection.getData(); + + assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); + assertEquals(2, packages.size()); + assertEquals(STUB_PACKAGE_NAME, packages.get(0).getAttributes().getName()); + assertEquals(STUB_PACKAGE_NAME_2, packages.get(1).getAttributes().getName()); + } + + @Test + void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByTags() { + savePackage(buildDbPackage(FULL_PACKAGE_ID, configuration.getId(), STUB_PACKAGE_NAME), vertx); + savePackage(buildDbPackage(FULL_PACKAGE_ID_2, configuration.getId(), STUB_PACKAGE_NAME_2), vertx); + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); + + mockGet(matching(packagesRmApi() + ".*"), SC_INTERNAL_SERVER_ERROR); + + var packageCollection = getWithOk(withTagFilters(packagesPath(), STUB_TAG_VALUE)).as(PackageCollection.class); + + assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); + } + + @Test + void shouldReturnPackagesOnSearchWithPagination() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_3, PACKAGE, STUB_TAG_VALUE); + + setUpPackages(vertx, configuration.getId()); + + var packageCollection = getWithOk(withTagFilters(packagesPath() + "?page=2&count=1", STUB_TAG_VALUE)) + .as(PackageCollection.class); + var packages = packageCollection.getData(); + + assertEquals(3, (int) packageCollection.getMeta().getTotalResults()); + assertEquals(1, packages.size()); + assertEquals(STUB_PACKAGE_NAME_2, packages.getFirst().getAttributes().getName()); + } + + @Test + void shouldReturnPackagesOnSearchByAccessTypeWithPagination() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.get(0).getId(), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID_2, PACKAGE, accessTypes.get(1).getId(), vertx); + + setUpPackages(vertx, configuration.getId()); + + var resourcePath = withAccessTypeFilters(packagesPath() + "?page=2&count=1", + STUB_ACCESS_TYPE_NAME, STUB_ACCESS_TYPE_NAME_2); + var packageCollection = getWithOk(resourcePath).as(PackageCollection.class); + var packages = packageCollection.getData(); + + assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); + assertEquals(1, packages.size()); + assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getAttributes().getName()); + } + + @Test + void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByAccessType() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.getFirst().getId(), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID_2, PACKAGE, accessTypes.getFirst().getId(), vertx); + + mockGet(matching(".*lists/.*"), SC_INTERNAL_SERVER_ERROR); + + var resourcePath = withAccessTypeFilters(packagesPath(), STUB_ACCESS_TYPE_NAME); + var packageCollection = getWithOk(resourcePath).as(PackageCollection.class); + + assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); + } + + @Test + void shouldReturn400OnInvalidFilterCustomParameter() { + var resourcePath = packagesPath() + "?filter[custom]=test"; + var response = getWithStatus(resourcePath, SC_BAD_REQUEST).asString(); + + assertTrue(response.contains("Invalid Query Parameter for filter[custom]: only 'true' is supported")); + } + + @Test + void shouldReturn400OnNotSupportedFilterCustomParameter() { + var resourcePath = packagesPath() + "?filter[custom]=false"; + var response = getWithStatus(resourcePath, SC_BAD_REQUEST).asString(); + + assertTrue(response.contains("Invalid Query Parameter for filter[custom]: only 'true' is supported")); + } + + @Test + void shouldReturnPackagesOnGetWithPackageId() { + mockGet(matching(rootProxyCustomLabelsRmApi()), readFile(GET_PROXIES_CUSTOMLABELS_RESPONSE)); + mockGet(matching(providerPackagesRmApi(STUB_VENDOR_ID) + ".*"), readFile(GET_PACKAGES_BY_PROVIDER_RESPONSE)); + + var packages = getWithOk(packagesPath() + "?q=a&count=5&page=1&filter[custom]=true").asString(); + + assertJsonEqual(readFile(EXPECTED_PACKAGES_COLLECTION_1), packages, true); + } + + @Test + void shouldReturnPackagesOnGetById() { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + + var packages = getWithOk(packagePath(FULL_PACKAGE_ID)).asString(); + + assertJsonEqual(readFile(EXPECTED_PACKAGE_BY_ID_STUB_FILE), packages); + } + + @Test + void shouldReturnPackageWithTagOnGetById() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + + var packages = getWithOk(packagePath(FULL_PACKAGE_ID)).as(Package.class); + + assertTrue(packages.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); + } + + @Test + void shouldReturnPackageWithAccessTypeOnGetById() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + var expectedAccessTypeId = accessTypes.getFirst().getId(); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, expectedAccessTypeId, vertx); + + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + var packageData = getWithOk(packagePath(FULL_PACKAGE_ID)).as(Package.class); + + assertNotNull(packageData.getIncluded()); + assertEquals(expectedAccessTypeId, packageData.getData().getRelationships().getAccessType().getData().getId()); + assertEquals(expectedAccessTypeId, ((LinkedHashMap<?, ?>) packageData.getIncluded().getFirst()).get("id")); + } + + @Test + void shouldAddPackageTagsOnPutTagsWhenPackageAlreadyHasTags() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + var newTags = List.of(STUB_TAG_VALUE, STUB_TAG_VALUE_2); + + sendPutTags(newTags); + + var tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); + assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); + } + + @Test + void shouldAddPackageDataOnPutTags() { + var tags = Collections.singletonList(STUB_TAG_VALUE); + + sendPutTags(tags); + + var packages = PackagesTestUtil.getPackages(vertx); + assertEquals(1, packages.size()); + assertEqualsPackageId(packages.getFirst().getId()); + assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getName()); + assertTrue(packages.getFirst().getContentType().equalsIgnoreCase(STUB_PACKAGE_CONTENT_TYPE)); + } + + @Test + void shouldUpdateTagsOnlyOnPutPackageTagsEndpoint() { + var tags = Collections.singletonList(STUB_TAG_VALUE); + + sendPutTags(tags); + var updatedPackage = sendPut(readFile(PACKAGE_STUB_FILE)); + + var packageTags = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); + assertThat(packageTags, is(tags)); + assertTrue(Objects.isNull(updatedPackage.getData().getAttributes().getTags())); + } + + @Test + void shouldDeleteAllPackageTagsOnPutTagsWhenRequestHasEmptyListOfTags() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, "test one"); + + sendPutTags(Collections.emptyList()); + + var tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); + assertTrue(tagsAfterRequest.isEmpty()); + } + + @Test + void shouldDoNothingOnPutWhenRequestHasNotTags() { + sendPutTags(null); + sendPutTags(null); + + var tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); + assertTrue(tagsAfterRequest.isEmpty()); + } + + @Test + void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() { + var tags = readJsonFile(PUT_PACKAGE_TAGS_REQUEST, PackageTagsPutRequest.class); + tags.getData().getAttributes().setName(""); + var error = putWithStatus(tagsPath(FULL_PACKAGE_ID), Json.encode(tags), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + } + + @Test + void shouldDeletePackageTagsOnDelete() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, "test one"); + mockGet(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + + var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); + mockPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), putBodyPattern, SC_NO_CONTENT); + + deleteWithNoContent(packagePath(FULL_PACKAGE_ID)); + + var tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); + assertTrue(tagsAfterRequest.isEmpty()); + } + + @Test + void shouldDeletePackageAccessTypeMappingOnDelete() { + var accessTypeId = insertAccessTypes(testData(configuration.getId()), vertx).getFirst().getId(); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypeId, vertx); + mockGet(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + + var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); + mockPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), putBodyPattern, SC_NO_CONTENT); + + deleteWithNoContent(packagePath(FULL_PACKAGE_ID)); + + var mappingsAfterRequest = AccessTypesTestUtil.getAccessTypeMappings(vertx); + assertTrue(mappingsAfterRequest.isEmpty()); + } + + @Test + void shouldDeletePackageOnDeleteRequest() { + sendPost(readFile(POST_PACKAGE_REQUEST)); + sendPutTags(Collections.singletonList(STUB_TAG_VALUE)); + + mockGet(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + mockPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), SC_NO_CONTENT); + + deleteWithNoContent(packagePath(FULL_PACKAGE_ID)); + + var packages = PackagesTestUtil.getPackages(vertx); + assertTrue(packages.isEmpty()); + } + + @Test + void shouldReturn404WhenPackageIsNotFoundOnRmApi() { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), SC_NOT_FOUND); + + var error = getWithStatus(packagePath(FULL_PACKAGE_ID), SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "not found"); + } + + @Test + void shouldReturnResourcesWhenIncludedFlagIsSetToResources() { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); + + var actual = getWithOk(withInclude(packagePath(FULL_PACKAGE_ID), "resources")).as(Package.class); + + var expectedPackage = readJsonFile(EXPECTED_PACKAGE_BY_ID_STUB_FILE, Package.class); + var expectedResources = readJsonFile(EXPECTED_RESOURCES_STUB_FILE, ResourceCollection.class); + expectedPackage.getIncluded().addAll(expectedResources.getData()); + + assertJsonEqual(Json.encode(expectedPackage), Json.encode(actual)); + } + + @Test + void shouldReturnProviderWhenIncludedFlagIsSetToProvider() { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + mockGet(matching(vendorsRmApi(STUB_VENDOR_ID)), readFile(VENDOR_BY_PACKAGE_ID_STUB_FILE)); + + var actual = getWithOk(withInclude(packagePath(FULL_PACKAGE_ID), "provider")).asString(); + + var expected = readFile(EXPECTED_PACKAGE_WITH_PROVIDER); + assertJsonEqual(expected, actual, true); + } + + @Test + void shouldSendDeleteRequestForPackage() { + mockGet(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); + mockPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), putBodyPattern, SC_NO_CONTENT); + + deleteWithNoContent(packagePath(FULL_PACKAGE_ID)); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), putBodyPattern); + } + + @Test + void shouldReturn400WhenPackageIdIsInvalid() { + var error = deleteWithStatus(packagePath("abc-def"), SC_BAD_REQUEST).asString(); + + assertTrue(error.contains("Package or provider id are invalid")); + } + + @Test + void shouldReturn400WhenPackageIsNotCustom() { + var packageData = readJsonFile(CUSTOM_PACKAGE_STUB_FILE, PackageData.class).toBuilder() + .isCustom(false).build(); + + mockGet(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), Json.encode(packageData)); + + var error = deleteWithStatus(packagePath(FULL_PACKAGE_ID), SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Package cannot be deleted"); + } + + @Test + void shouldReturn200WhenSelectingPackage() { + boolean updatedIsSelected = true; + + var packageData = readJsonFile(PACKAGE_STUB_FILE, PackageData.class).toBuilder() + .isSelected(updatedIsSelected).build(); + var updatedPackageValue = Json.encode(packageData); + mockUpdateScenario(readFile(PACKAGE_STUB_FILE), updatedPackageValue); + + var actual = putWithOk(packagePath(FULL_PACKAGE_ID), readFile(PUT_PACKAGE_SELECTED_REQUEST)).as(Package.class); + + assertEquals(updatedIsSelected, actual.getData().getAttributes().getIsSelected()); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), + equalToJson(readFile(PUT_PACKAGE_SELECTED_RMAPI_REQUEST), true, true)); + } + + @Test + void shouldUpdateAllAttributesInSelectedPackage() { + boolean updatedSelected = true; + boolean updatedAllowEbscoToAddTitles = true; + boolean updatedHidden = true; + String updatedBeginCoverage = "2003-01-01"; + String updatedEndCoverage = "2004-01-01"; + + var updatedPackageValue = + preparePackageData(updatedSelected, updatedHidden, updatedBeginCoverage, updatedEndCoverage, + updatedAllowEbscoToAddTitles); + mockUpdateScenario(readFile(PACKAGE_STUB_FILE), updatedPackageValue); + + var actual = putWithOk(packagePath(FULL_PACKAGE_ID), readFile(PUT_PACKAGE_SELECTED_REQUEST)).as(Package.class); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), + equalToJson(readFile(PUT_PACKAGE_SELECTED_RMAPI_REQUEST), true, true)); + + assertEquals(updatedSelected, actual.getData().getAttributes().getIsSelected()); + assertEquals(updatedAllowEbscoToAddTitles, actual.getData().getAttributes().getAllowKbToAddTitles()); + assertEquals(updatedBeginCoverage, actual.getData().getAttributes().getCustomCoverage().getBeginCoverage()); + assertEquals(updatedEndCoverage, actual.getData().getAttributes().getCustomCoverage().getEndCoverage()); + } + + @Test + @SuppressWarnings("checkstyle:methodLength") + void shouldUpdateAllAttributesInSelectedPackageAndCreateNewAccessTypeMapping() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + var accessTypeId = accessTypes.getFirst().getId(); + + boolean updatedSelected = true; + boolean updatedAllowEbscoToAddTitles = true; + boolean updatedHidden = true; + String updatedBeginCoverage = "2003-01-01"; + String updatedEndCoverage = "2004-01-01"; + + var updatedPackageValue = + preparePackageData(updatedSelected, updatedHidden, updatedBeginCoverage, updatedEndCoverage, + updatedAllowEbscoToAddTitles); + mockUpdateScenario(readFile(PACKAGE_STUB_FILE), updatedPackageValue); + + var putBody = format(readFile(PUT_PACKAGE_SELECTED_WITH_ACCESS_TYPE_REQUEST), accessTypeId); + var actualPackage = putWithOk(packagePath(FULL_PACKAGE_ID), putBody).as(Package.class); + + assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); + assertEquals(updatedAllowEbscoToAddTitles, actualPackage.getData().getAttributes().getAllowKbToAddTitles()); + assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); + assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(1, accessTypeMappingsInDb.size()); + assertEquals(actualPackage.getData().getId(), accessTypeMappingsInDb.getFirst().getRecordId()); + assertEqualsUuid(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); + assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); + assertNotNull(actualPackage.getIncluded()); + assertEquals(accessTypeId, actualPackage.getData().getRelationships().getAccessType().getData().getId()); + assertEquals(accessTypeId, ((LinkedHashMap<?, ?>) actualPackage.getIncluded().getFirst()).get("id")); + } + + @Test + void shouldDeleteAccessTypeMappingWhenRmApiSend404() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + var currentAccessTypeId = accessTypes.get(0).getId(); + var newAccessTypeId = accessTypes.get(1).getId(); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, currentAccessTypeId, vertx); + + var packageData = readJsonFile(CUSTOM_PACKAGE_STUB_FILE, PackageData.class).toBuilder() + .contentType("streamingmedia") + .build(); + + var updatedPackageValue = Json.encode(packageData); + mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); + + var putBody = format(readFile(PUT_PACKAGE_CUSTOM_WITH_ACCESS_TYPE_REQUEST), newAccessTypeId); + wm.stubFor(get(urlPathEqualTo(packageRmApi(STUB_PACKAGE_ID))) + .inScenario("Put package") + .whenScenarioStateIs(STARTED) + .willReturn(aResponse().withBody(readFile(CUSTOM_PACKAGE_STUB_FILE))) + .willSetStateTo("Not found")); + wm.stubFor(get(urlPathEqualTo(packageRmApi(STUB_PACKAGE_ID))) + .inScenario("Put package") + .whenScenarioStateIs("Not found") + .willReturn(aResponse().withStatus(SC_NOT_FOUND))); + + putWithStatus(packagePath(FULL_PACKAGE_ID), putBody, SC_NOT_FOUND); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(0, accessTypeMappingsInDb.size()); + } + + @Test + void shouldReturn422OnPutWhenUnselectNonCustomPackageIsHidden() { + var putBody = readFile(PUT_PACKAGE_NOT_SELECTED_NON_EMPTY_REQUEST); + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(PACKAGE_STUB_FILE)); + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), 0); + + assertErrorContainsTitle(error, "Invalid visibility"); + } + + @Test + void shouldReturn422OnPutWhenCustomPackageUpdateLikeNotCustom() { + var putBody = readFile(PUT_PACKAGE_SELECTED_REQUEST); + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), 0); + + assertErrorContainsTitle(error, "Package isCustom not matched"); + } + + @Test + void shouldPassIsFullPackageAttributeToRmApi() { + var updatedPackage = readJsonFile(PACKAGE_STUB_FILE, PackageData.class).toBuilder() + .isSelected(true).build(); + mockUpdateScenario(readFile(PACKAGE_STUB_FILE), Json.encode(updatedPackage)); + var request = readJsonFile(PUT_PACKAGE_SELECTED_REQUEST, PackagePutRequest.class); + request.getData().getAttributes().setIsFullPackage(false); + + putWithOk(packagePath(FULL_PACKAGE_ID), Json.encode(request)).as(Package.class); + + var rmApiPutRequest = readJsonFile(PUT_PACKAGE_SELECTED_RMAPI_REQUEST, PackagePut.class).toBuilder() + .isFullPackage(false).build(); + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), + equalToJson(Json.encode(rmApiPutRequest), true, true)); + } + + @Test + void shouldUpdateAllAttributesInCustomPackage() { + boolean updatedSelected = true; + boolean updatedHidden = true; + String updatedBeginCoverage = "2003-01-01"; + String updatedEndCoverage = "2004-01-01"; + String updatedPackageName = "name of the ages forever and ever"; + + var updatedPackageValue = prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, + updatedEndCoverage, updatedPackageName); + mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); + + var actualPackage = putWithOk(packagePath(FULL_PACKAGE_ID), + readFile(PUT_PACKAGE_CUSTOM_MULTIPLE_ATTRIBUTES_REQUEST)).as(Package.class); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), + equalToJson(readFile(PUT_PACKAGE_CUSTOM_RMAPI_REQUEST), true, true)); + + assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); + assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); + assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); + assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); + assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); + } + + @Test + @SuppressWarnings("checkstyle:methodLength") + void shouldUpdateAllAttributesInCustomPackageAndCreateNewAccessTypeMapping() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + var accessTypeId = accessTypes.getFirst().getId(); + + boolean updatedSelected = true; + boolean updatedHidden = true; + String updatedBeginCoverage = "2003-01-01"; + String updatedEndCoverage = "2004-01-01"; + String updatedPackageName = "name of the ages forever and ever"; + + var updatedPackageValue = prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, + updatedEndCoverage, updatedPackageName); + mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); + + var putBody = format(readFile(PUT_PACKAGE_CUSTOM_WITH_ACCESS_TYPE_REQUEST), + accessTypeId); + var actualPackage = putWithOk(packagePath(FULL_PACKAGE_ID), putBody).as(Package.class); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), + equalToJson(readFile(PUT_PACKAGE_CUSTOM_RMAPI_REQUEST), true, true)); + + assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); + assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); + assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); + assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); + assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(1, accessTypeMappingsInDb.size()); + assertEquals(actualPackage.getData().getId(), accessTypeMappingsInDb.getFirst().getRecordId()); + assertEqualsUuid(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); + assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); + assertNotNull(actualPackage.getIncluded()); + assertEquals(accessTypeId, actualPackage.getData().getRelationships().getAccessType().getData().getId()); + assertEquals(accessTypeId, ((LinkedHashMap<?, ?>) actualPackage.getIncluded().getFirst()).get("id")); + } + + @Test + @SuppressWarnings("checkstyle:methodLength") + void shouldUpdateAllAttributesInCustomPackageAndDeleteAccessTypeMapping() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + var accessTypeId = accessTypes.getFirst().getId(); + + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypeId, vertx); + + boolean updatedSelected = true; + boolean updatedHidden = true; + String updatedBeginCoverage = "2003-01-01"; + String updatedEndCoverage = "2004-01-01"; + String updatedPackageName = "name of the ages forever and ever"; + + var updatedPackageValue = prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, + updatedEndCoverage, updatedPackageName); + mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); + + var putBody = readFile(PUT_PACKAGE_CUSTOM_MULTIPLE_ATTRIBUTES_REQUEST); + var actualPackage = putWithOk(packagePath(FULL_PACKAGE_ID), putBody).as(Package.class); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), + equalToJson(readFile(PUT_PACKAGE_CUSTOM_RMAPI_REQUEST), true, true)); + + assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); + assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); + assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); + assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); + assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(0, accessTypeMappingsInDb.size()); + + assertNotNull(actualPackage.getIncluded()); + assertEquals(0, actualPackage.getIncluded().size()); + assertNull(actualPackage.getData().getRelationships().getAccessType()); + } + + @Test + @SuppressWarnings("checkstyle:methodLength") + void shouldUpdateAllAttributesInCustomPackageAndUpdateAccessTypeMapping() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + final var currentAccessTypeId = accessTypes.get(0).getId(); + final var newAccessTypeId = accessTypes.get(1).getId(); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, currentAccessTypeId, vertx); + + boolean updatedSelected = true; + boolean updatedHidden = true; + String updatedBeginCoverage = "2003-01-01"; + String updatedEndCoverage = "2004-01-01"; + String updatedPackageName = "name of the ages forever and ever"; + + var updatedPackageValue = prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, + updatedEndCoverage, updatedPackageName); + mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); + + var putBody = format(readFile(PUT_PACKAGE_CUSTOM_WITH_ACCESS_TYPE_REQUEST), newAccessTypeId); + var actualPackage = putWithOk(packagePath(FULL_PACKAGE_ID), putBody).as(Package.class); + + verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), + equalToJson(readFile(PUT_PACKAGE_CUSTOM_RMAPI_REQUEST), true, true)); + + assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); + assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); + assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); + assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); + assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(1, accessTypeMappingsInDb.size()); + assertEquals(actualPackage.getData().getId(), accessTypeMappingsInDb.getFirst().getRecordId()); + assertEqualsUuid(newAccessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); + assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); + assertNotNull(actualPackage.getIncluded()); + assertEquals(newAccessTypeId, actualPackage.getData().getRelationships().getAccessType().getData().getId()); + assertEquals(newAccessTypeId, ((LinkedHashMap<?, ?>) actualPackage.getIncluded().getFirst()).get("id")); + } + + @Test + void shouldReturn400OnPutPackageWithNotExistedAccessType() { + var requestBody = readFile(PUT_PACKAGE_WITH_NOT_EXISTED_ACCESS_TYPE_REQUEST); + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(CUSTOM_PACKAGE_STUB_FILE)); + + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), requestBody, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Access type not found: id = 99999999-9999-1999-a999-999999999999"); + } + + @Test + void shouldReturn422OnPutPackageWithInvalidAccessTypeId() { + var requestBody = readFile(PUT_PACKAGE_WITH_INVALID_ACCESS_TYPE_REQUEST); + + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), requestBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); + + assertEquals(1, error.getErrors().size()); + assertEquals( + "must match \"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[1-5][a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$\"", + error.getErrors().getFirst().getMessage()); + } + + @Test + void shouldReturn400WhenRmApiReturns400() { + var urlPattern = WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)); + + mockGet(urlPattern, readFile(PACKAGE_STUB_FILE)); + mockPut(urlPattern, SC_BAD_REQUEST); + + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), readFile(PUT_PACKAGE_SELECTED_REQUEST), SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertEquals(1, error.getErrors().size()); + } + + @Test + void shouldReturn200WhenPackagePostIsValid() { + var createdPackage = sendPost(readFile(POST_PACKAGE_REQUEST)).as(Package.class); + + assertTrue(Objects.isNull(createdPackage.getData().getAttributes().getTags())); + wm.verify(1, postRequestedFor(urlPathEqualTo(packageRmApiV1(STUB_VENDOR_ID))) + .withRequestBody(equalToJson(readFile(POST_PACKAGE_RMAPI_REQUEST), false, true))); + } + + @Test + void shouldReturn200OnPostPackageWithExistedAccessType() { + var accessTypeId = insertAccessType(testData(configuration.getId()).getFirst(), vertx); + + var requestBody = format(readFile(POST_PACKAGE_WITH_ACCESS_TYPE_REQUEST), accessTypeId); + var createdPackage = sendPost(requestBody).as(Package.class); + + assertTrue(Objects.isNull(createdPackage.getData().getAttributes().getTags())); + wm.verify(1, postRequestedFor(urlPathEqualTo(packageRmApiV1(STUB_VENDOR_ID))) + .withRequestBody(equalToJson(readFile(POST_PACKAGE_RMAPI_REQUEST), false, true))); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(1, accessTypeMappingsInDb.size()); + assertEqualsUuid(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); + assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); + assertNotNull(createdPackage.getIncluded()); + assertEquals(accessTypeId, createdPackage.getData().getRelationships().getAccessType().getData().getId()); + assertEquals(accessTypeId, ((LinkedHashMap<?, ?>) createdPackage.getIncluded().getFirst()).get("id")); + } + + @Test + void shouldReturn400OnPostPackageWithNotExistedAccessType() { + var requestBody = readFile(POST_PACKAGE_WITH_NOT_EXISTED_ACCESS_TYPE_REQUEST); + mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE)); + + var error = postWithStatus(packagesPath(), requestBody, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Access type not found: id = 99999999-9999-1999-a999-999999999999"); + } + + @Test + void shouldReturn422OnPostPackageWithInvalidAccessTypeId() { + var requestBody = readFile(POST_PACKAGE_WITH_INVALID_ACCESS_TYPE_REQUEST); + + var error = postWithStatus(packagesPath(), requestBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); + + assertEquals(1, error.getErrors().size()); + assertEquals( + "must match \"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[1-5][a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$\"", + error.getErrors().getFirst().getMessage()); + } + + @Test + void shouldReturn400WhenPackagePostDataIsInvalid() { + mockGet(WireMock.equalTo(rootProxyCustomLabelsRmApi()), readFile(GET_PACKAGE_PROVIDER_RESPONSE)); + mockPost(WireMock.equalTo(packageRmApiV1(STUB_VENDOR_ID)), + equalToJson(""" + { + "contentType" : 8, + "packageName" : "TEST_NAME", + "customCoverage" : { + "beginCoverage" : "2017-12-23", + "endCoverage" : "2018-03-30" + } + }""", + false, true), readFile(POST_PACKAGE_400_RESPONSE), SC_BAD_REQUEST); + + var response = postWithStatus(packagesPath(), readFile(POST_PACKAGE_REQUEST), SC_BAD_REQUEST); + assertErrorContainsTitle(response.as(JsonapiError.class), "name already exists"); + } + + @Test + void shouldReturnDefaultResourcesOnGetWithResources() { + String query = "?searchfield=titlename&selection=all&resourcetype=all" + + "&searchtype=advanced&search=&offset=1&count=25&orderby=titlename"; + shouldReturnResourcesOnGetWithResources(resourcesPath(FULL_PACKAGE_ID), query); + } + + @Test + void shouldReturnResourcesWithPagingOnGetWithResources() { + var resourcesUrl = resourcesPath(FULL_PACKAGE_ID) + "?page=2"; + var query = "?searchfield=titlename&selection=all&resourcetype=all" + + "&searchtype=advanced&search=&offset=2&count=25&orderby=titlename"; + shouldReturnResourcesOnGetWithResources(resourcesUrl, query); + } + + @Test + void shouldReturnEmptyListWhenResourcesAreNotFound() { + mockResourceById(RESOURCES_BY_PACKAGE_ID_EMPTY_STUB_FILE); + + var actual = getWithOk(resourcesPath(FULL_PACKAGE_ID)).as(ResourceCollection.class); + assertTrue(actual.getData().isEmpty()); + assertEquals(0, (int) actual.getMeta().getTotalResults()); + } + + @Test + void shouldReturnResourcesWithTagsOnGetWithResources() { + saveTag(vertx, "295-2545963-2099944", RESOURCE, STUB_TAG_VALUE); + saveTag(vertx, "295-2545963-2172685", RESOURCE, STUB_TAG_VALUE_2); + saveTag(vertx, "295-2545963-2172685", RESOURCE, STUB_TAG_VALUE_3); + + String query = "?searchfield=titlename&selection=all&resourcetype=all&searchtype=advanced" + + "&search=&offset=1&count=25&orderby=titlename"; + + mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); + + var actual = getWithOk(resourcesPath(FULL_PACKAGE_ID)).asString(); + var expected = readFile(EXPECTED_RESOURCES_WITH_TAGS_STUB_FILE); + + assertJsonEqual(expected, actual); + + wm.verify(1, getRequestedFor(urlEqualTo(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + query))); + } + + @Test + void shouldReturnResourcesWithAccessTypesOnGetWithResources() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.getFirst().getId(), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.getFirst().getId(), vertx); + + mockResourceById(GET_TITLE_BY_ID_RESPONSE); + + var resourcePath = withAccessTypeFilters(resourcesPath(FULL_PACKAGE_ID), STUB_ACCESS_TYPE_NAME); + var resourceCollection = getWithOk(resourcePath).as(ResourceCollection.class); + var resources = resourceCollection.getData(); + + assertEquals(2, (int) resourceCollection.getMeta().getTotalResults()); + assertEquals(2, resources.size()); + assertThat(resources, everyItem(hasProperty("id", + anyOf(equalTo(STUB_MANAGED_RESOURCE_ID), equalTo(STUB_MANAGED_RESOURCE_ID_2)) + ))); + } + + @Test + void shouldReturnResourcesWithAccessTypesOnGetWithResourcesWithPagination() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.get(0).getId(), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.get(1).getId(), vertx); + + mockResourceById(GET_TITLE_BY_ID_RESPONSE); + + var resourcePath = withAccessTypeFilters(resourcesPath(FULL_PACKAGE_ID) + "?page=2&count=1", + STUB_ACCESS_TYPE_NAME, STUB_ACCESS_TYPE_NAME_2); + var resourceCollection = getWithOk(resourcePath).as(ResourceCollection.class); + var resources = resourceCollection.getData(); + + assertEquals(2, (int) resourceCollection.getMeta().getTotalResults()); + assertEquals(1, resources.size()); + assertThat(resources, everyItem(hasProperty("id", equalTo(STUB_MANAGED_RESOURCE_ID)))); + } + + @Test + void shouldReturnResourcesWithAccessTypesOnGetWithResources1() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping("295-2545963-2099944", RESOURCE, accessTypes.get(0).getId(), vertx); + insertAccessTypeMapping("295-2545963-2172685", RESOURCE, accessTypes.get(1).getId(), vertx); + + mockResourceById(GET_TITLE_BY_ID_RESPONSE); + mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); + + var resourceCollection = getWithOk(resourcesPath(FULL_PACKAGE_ID)).as(ResourceCollection.class); + var resources = resourceCollection.getData(); + + assertEquals(5, (int) resourceCollection.getMeta().getTotalResults()); + assertEquals(5, resources.size()); + + assertEquals("295-2545963-2099944", resources.getFirst().getId()); + assertEquals(1, resources.get(0).getIncluded().size()); + assertEquals(accessTypes.getFirst().getId(), + ((LinkedHashMap<?, ?>) resources.get(0).getIncluded().getFirst()).get("id")); + assertEquals("295-2545963-2172685", resources.get(2).getId()); + assertEquals(1, resources.get(2).getIncluded().size()); + assertEquals(accessTypes.get(1).getId(), + ((LinkedHashMap<?, ?>) resources.get(2).getIncluded().getFirst()).get("id")); + } + + @Test + void shouldReturnFilteredResourcesWithNonEmptyCustomerResourceList() { + mockResourceById(RESOURCES_BY_PACKAGE_ID_EMPTY_CUSTOMER_RESOURCE_LIST_STUB_FILE); + + var resourceCollection = getWithOk(resourcesPath(FULL_PACKAGE_ID)).as(ResourceCollection.class); + + var metaTotalResults = resourceCollection.getMeta(); + assertEquals(3, metaTotalResults.getTotalResults()); + } + + @Test + void shouldReturn404OnGetWithResourcesWhenPackageNotFound() { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), SC_NOT_FOUND); + + var error = getWithStatus(resourcesPath(FULL_PACKAGE_ID), SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Package not found"); + } + + @Test + void shouldReturn400OnGetWithResourcesWhenCountOutOfRange() { + var packageResourcesUrl = resourcesPath(FULL_PACKAGE_ID) + "?count=500"; + + var error = getWithStatus(packageResourcesUrl, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "is not valid"); + } + + @Test + void shouldReturn400OnGetWithResourcesWhenRmApi400() { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), + readFile(GET_PACKAGE_RESOURCES_400_RESPONSE), SC_BAD_REQUEST); + + var error = getWithStatus(resourcesPath(FULL_PACKAGE_ID), SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Parameter Count is outside the range 1-100."); + } + + @Test + void shouldReturnUnauthorizedOnGetWithResourcesWhenRmApi401() { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), SC_UNAUTHORIZED); + + var error = getWithStatus(resourcesPath(FULL_PACKAGE_ID), SC_FORBIDDEN).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturnUnauthorizedOnGetWithResourcesWhenRmApi403() { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), SC_FORBIDDEN); + + var error = getWithStatus(resourcesPath(FULL_PACKAGE_ID), SC_FORBIDDEN).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldFetchPackagesInBulk() { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(PACKAGE_STUB_FILE)); + mockGet(matching(packageRmApi(STUB_PACKAGE_ID_2)), readFile(PACKAGE_2_STUB_FILE)); + + var postBody = readFile(POST_PACKAGES_BULK_REQUEST); + var actualResponse = postWithOk(packagesBulkPath(), postBody).asString(); + + assertJsonEqual(readFile(EXPECTED_POST_PACKAGES_BULK), actualResponse, true); + } + + @Test + void shouldReturn422OnFetchPackagesInBulkWithInvalidIdFormat() { + var postBody = readFile(POST_PACKAGES_BULK_WITH_INVALID_ID_REQUEST); + + var error = postWithStatus(packagesBulkPath(), postBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); + + assertEquals("elements in list must match pattern", error.getErrors().getFirst().getMessage()); + } + + @Test + void shouldReturnPackagesAndFailedIdsOnFetchPackagesInBulk() { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(PACKAGE_STUB_FILE)); + mockGet(matching(packageRmApi(STUB_PACKAGE_ID_2)), readFile(PACKAGE_2_STUB_FILE)); + + mockGet(WireMock.equalTo(packageRmApi(9999999)), readFile(GET_PACKAGE_NOT_FOUND_RESPONSE), SC_NOT_FOUND); + + var postBody = readFile(POST_PACKAGES_BULK_WITH_NON_EXISTING_ID_REQUEST); + var actualResponse = postWithOk(packagesBulkPath(), postBody).asString(); + + assertJsonEqual(readFile(EXPECTED_POST_PACKAGES_BULK_FAILED), actualResponse); + } + + @Test + void shouldReturnEmptyPackagesOnFetchPackagesInBulkIfNoPackageIds() { + var postBody = readFile(POST_PACKAGES_BULK_EMPTY_REQUEST); + var actualResponse = postWithOk(packagesBulkPath(), postBody).asString(); + + assertJsonEqual(readFile(EXPECTED_POST_PACKAGES_BULK_EMPTY), actualResponse); + } + + private String getPackageResponse(String packageName, int packageId, int providerId) { + PackageData packageData = readJsonFile(PACKAGE_STUB_FILE, PackageData.class); + return Json.encode(packageData.toBuilder() + .packageName(packageName) + .packageId(packageId) + .vendorId(providerId) + .build()); + } + + private void setUpPackages(Vertx vertx, String credentialsId) { + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_2, STUB_VENDOR_ID_2, STUB_PACKAGE_NAME_2); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_3, STUB_VENDOR_ID_3, STUB_PACKAGE_NAME_3); + } + + private void setUpPackage(Vertx vertx, String credentialsId, int packageId, int vendorId, String packageName) { + var dbPackage = buildDbPackage(vendorId + "-" + packageId, credentialsId, packageName); + PackagesTestUtil.savePackage(dbPackage, vertx); + mockPackageWithName(packageId, vendorId, packageName); + } + + private void mockPackageWithName(int stubPackageId, int stubProviderId, String stubPackageName) { + mockGet(WireMock.equalTo(packageRmApi(stubPackageId)), + getPackageResponse(stubPackageName, stubPackageId, stubProviderId)); + } + + private static String packagesPath() { + return "eholdings/packages"; + } + + private static String packagesBulkPath() { + return "/eholdings/packages/bulk/fetch"; + } + + private static String packagePath(String packageId) { + return packagesPath() + "/" + packageId; + } + + private static String tagsPath(String packageId) { + return packagePath(packageId) + "/tags"; + } + + private static String resourcesPath(String packageId) { + return packagesPath() + "/" + packageId + "/resources"; + } + + private String prepareCustomPackageData(boolean updatedSelected, boolean updatedHidden, String updatedBeginCoverage, + String updatedEndCoverage, String updatedPackageName) { + var packageData = readJsonFile(CUSTOM_PACKAGE_STUB_FILE, PackageData.class); + var visibilities = packageData.getVisibilityDetails().stream() + .map(visibilityDetail -> visibilityDetail.toBuilder().hidden(updatedHidden).build()) + .toList(); + packageData = packageData.toBuilder() + .isSelected(updatedSelected) + .visibilityDetails(visibilities) + .customCoverage(CoverageDates.builder() + .beginCoverage(updatedBeginCoverage) + .endCoverage(updatedEndCoverage) + .build()) + .packageName(updatedPackageName) + .contentType("streamingmedia") + .build(); + + return Json.encode(packageData); + } + + private String preparePackageData(boolean updatedSelected, boolean updatedHidden, String updatedBeginCoverage, + String updatedEndCoverage, boolean updatedAllowEbscoToAddTitles) { + var packageData = readJsonFile(PACKAGE_STUB_FILE, PackageData.class); + var visibilities = packageData.getVisibilityDetails().stream() + .map(visibilityDetail -> visibilityDetail.toBuilder().hidden(updatedHidden).build()) + .toList(); + packageData = packageData.toBuilder() + .isSelected(updatedSelected) + .customCoverage(CoverageDates.builder() + .beginCoverage(updatedBeginCoverage) + .endCoverage(updatedEndCoverage) + .build()) + .allowEbscoToAddTitles(updatedAllowEbscoToAddTitles) + .visibilityDetails(visibilities) + .build(); + + return Json.encode(packageData); + } + + private void shouldReturnResourcesOnGetWithResources(String getUrl, String rmApiQuery) { + mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); + + var actual = getWithOk(getUrl).asString(); + var expected = readFile(EXPECTED_RESOURCES_STUB_FILE); + + assertJsonEqual(expected, actual); + + wm.verify(1, getRequestedFor(urlEqualTo(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + rmApiQuery))); + } + + private void mockResourceById(String stubFile) { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), readFile(stubFile)); + } + + private void mockUpdateScenario(String initialPackage, String updatedPackage) { + mockUpdateScenario(initialPackage); + + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), updatedPackage); + } + + private void mockUpdateScenario(String initialPackage) { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), initialPackage); + mockPut(matching(packageRmApi(STUB_PACKAGE_ID)), SC_NO_CONTENT); + } + + private Package sendPut(String mockUpdatedPackage) { + mockUpdateScenario(readFile(PACKAGE_STUB_FILE), mockUpdatedPackage); + + var packageToBeUpdated = readJsonFile(PUT_PACKAGE_SELECTED_REQUEST, PackagePutRequest.class); + + return putWithOk(packagePath(FULL_PACKAGE_ID), Json.encode(packageToBeUpdated)).as(Package.class); + } + + private void sendPutTags(List<String> newTags) { + var tags = readJsonFile(PUT_PACKAGE_TAGS_REQUEST, PackageTagsPutRequest.class); + + if (newTags != null) { + tags.getData().getAttributes().setTags(new Tags() + .withTagList(newTags)); + } + + putWithOk(tagsPath(FULL_PACKAGE_ID), Json.encode(tags)).as(PackageTags.class); + } + + private ExtractableResponse<Response> sendPost(String requestBody) { + mockGet(matching(rootProxyCustomLabelsRmApi()), readFile(GET_PACKAGE_PROVIDER_RESPONSE)); + mockPost(WireMock.equalTo(packageRmApiV1(STUB_VENDOR_ID)), readFile(POST_PACKAGE_CREATED_RESPONSE), SC_OK); + mockGet(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), readFile(PACKAGE_STUB_FILE)); + + var request = Json.decodeValue(requestBody, PackagePostRequest.class); + return postWithOk(packagesPath(), Json.encode(request)); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java new file mode 100644 index 000000000..af3f22767 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java @@ -0,0 +1,528 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static org.apache.commons.lang3.RandomStringUtils.insecure; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.RecordType.PACKAGE; +import static org.folio.repository.RecordType.PROVIDER; +import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; +import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.repository.packages.PackageTableConstants.PACKAGES_TABLE_NAME; +import static org.folio.repository.providers.ProviderTableConstants.PROVIDERS_TABLE_NAME; +import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; +import static org.folio.rest.util.RestConstants.PROVIDERS_TYPE; +import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME; +import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME_2; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; +import static org.folio.util.AccessTypesTestUtil.testData; +import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssertTestUtil.assertJsonEqual; +import static org.folio.util.KbCredentialsTestUtil.getDefaultKbConfiguration; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.ProvidersTestUtil.buildDbProvider; +import static org.folio.util.ProvidersTestUtil.saveProvider; +import static org.folio.util.TagsTestUtil.getTagsForRecordType; +import static org.folio.util.TagsTestUtil.saveTag; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.tomakehurst.wiremock.matching.RegexPattern; +import io.vertx.core.Vertx; +import io.vertx.core.json.Json; +import java.util.Arrays; +import java.util.List; +import org.folio.holdingsiq.model.PackageData; +import org.folio.holdingsiq.model.VendorById; +import org.folio.rest.jaxrs.model.AccessType; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.rest.jaxrs.model.KbCredentials; +import org.folio.rest.jaxrs.model.PackageCollection; +import org.folio.rest.jaxrs.model.PackageTags; +import org.folio.rest.jaxrs.model.PackageTagsPutRequest; +import org.folio.rest.jaxrs.model.Provider; +import org.folio.rest.jaxrs.model.ProviderCollection; +import org.folio.rest.jaxrs.model.ProviderPutRequest; +import org.folio.rest.jaxrs.model.ProviderTagsPutRequest; +import org.folio.rest.jaxrs.model.Tags; +import org.folio.rest.jaxrs.model.Token; +import org.folio.util.IntegrationTestBase; +import org.folio.util.PackagesTestUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class EholdingsProvidersImplIntegrationTest extends IntegrationTestBase { + + // API endpoint paths + private static final String PROVIDER_PATH = "eholdings/providers"; + private static final String PROVIDER_BY_ID = PROVIDER_PATH + "/" + STUB_VENDOR_ID; + private static final String PROVIDER_PACKAGES = PROVIDER_BY_ID + "/packages"; + + // RM API response files + private static final String GET_VENDORS_RESPONSE = "responses/rmapi/vendors/get-vendors-response.json"; + private static final String GET_VENDOR_BY_ID_RESPONSE = "responses/rmapi/vendors/get-vendor-by-id-response.json"; + private static final String GET_VENDOR_UPDATED_RESPONSE = "responses/rmapi/vendors/get-vendor-updated-response.json"; + private static final String PUT_VENDOR_NOT_ALLOWED_RESPONSE = + "responses/rmapi/vendors/put-vendor-token-not-allowed-response.json"; + private static final String PUT_VENDOR_TOKEN_PROXY_REQUEST = "requests/rmapi/vendors/put-vendor-token-proxy.json"; + private static final String GET_PACKAGES_BY_PROVIDER_EMPTY = + "responses/rmapi/packages/get-packages-by-provider-id-empty.json"; + private static final String STUB_PACKAGE_RESPONSE = "responses/rmapi/packages/get-packages-by-provider-id.json"; + + // KB-EBSCO expected response files + private static final String EXPECTED_PROVIDER = "responses/kb-ebsco/providers/expected-provider.json"; + private static final String EXPECTED_PROVIDER_WITH_PACKAGES = + "responses/kb-ebsco/providers/expected-provider-with-packages.json"; + private static final String EXPECTED_UPDATED_PROVIDER = + "responses/kb-ebsco/providers/expected-updated-provider.json"; + private static final String EXPECTED_PACKAGE_COLLECTION = + "responses/kb-ebsco/packages/expected-package-collection-with-one-element.json"; + private static final String EXPECTED_PACKAGE_COLLECTION_WITH_TAGS = + "responses/kb-ebsco/packages/expected-package-collection-with-one-element-with-tags.json"; + + // Request payload files + private static final String PUT_PROVIDER = "requests/kb-ebsco/provider/put-provider.json"; + private static final String PUT_PROVIDER_TAGS = "requests/kb-ebsco/provider/put-provider-tags.json"; + private static final String STUB_PACKAGE_JSON_PATH = "responses/rmapi/packages/get-package-by-id-response.json"; + + private KbCredentials configuration; + + @BeforeEach + void setUp() { + setupDefaultKbConfiguration(getWiremockUrl(), vertx); + configuration = getDefaultKbConfiguration(vertx); + } + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); + clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); + clearDataFromTable(vertx, TAGS_TABLE_NAME); + clearDataFromTable(vertx, PROVIDERS_TABLE_NAME); + clearDataFromTable(vertx, PACKAGES_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnProvidersOnGet() { + mockGet(equalTo(vendorsRmApi()), readFile(GET_VENDORS_RESPONSE)); + + var collection = getWithOk(PROVIDER_PATH + "?q=e&page=1&sort=name").as(ProviderCollection.class); + var provider = collection.getData().getFirst(); + + assertEquals(115, (int) collection.getMeta().getTotalResults()); + assertEquals(PROVIDERS_TYPE, provider.getType()); + assertEquals("131872", provider.getId()); + + var attributes = provider.getAttributes(); + assertEquals("Editions de L'Universite de Bruxelles", attributes.getName()); + assertEquals(1, (int) attributes.getPackagesTotal()); + assertEquals(0, (int) attributes.getPackagesSelected()); + assertEquals(false, attributes.getSupportsCustomPackages()); + assertEquals("sampleToken", attributes.getProviderToken().getValue()); + } + + @Test + void shouldReturnProvidersOnSearchByTagsOnly() { + saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); + saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE); + saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE_2); + saveTag(vertx, STUB_VENDOR_ID_3, PROVIDER, STUB_TAG_VALUE_3); + + setUpTaggedProviders(); + + var endpoint = withTagFilters(PROVIDER_PATH, STUB_TAG_VALUE, STUB_TAG_VALUE_2); + var collection = getWithOk(endpoint).as(ProviderCollection.class); + + var providers = collection.getData(); + + assertEquals(2, (int) collection.getMeta().getTotalResults()); + assertEquals(2, providers.size()); + assertEquals(STUB_VENDOR_NAME, providers.get(0).getAttributes().getName()); + assertEquals(STUB_VENDOR_NAME_2, providers.get(1).getAttributes().getName()); + } + + @Test + void shouldReturnPackagesOnSearchByProviderIdAndTagsOnly() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE_2); + saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_3, PACKAGE, STUB_TAG_VALUE_2); + + setUpPackages(vertx, configuration.getId()); + + var endpoint = withTagFilters(PROVIDER_PACKAGES, STUB_TAG_VALUE); + var packageCollection = getWithOk(endpoint).as(PackageCollection.class); + var packages = packageCollection.getData(); + + assertEquals(1, (int) packageCollection.getMeta().getTotalResults()); + assertEquals(1, packages.size()); + assertThat(packages.getFirst().getAttributes().getTags().getTagList(), + containsInAnyOrder(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); + assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getAttributes().getName()); + } + + @Test + void shouldReturnPackagesOnSearchByProviderIdAndTagsWithPagination() { + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_4, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID_5, PACKAGE, STUB_TAG_VALUE_2); + + var credentialsId = configuration.getId(); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_2, STUB_VENDOR_ID, STUB_PACKAGE_NAME_2); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_3, STUB_VENDOR_ID, STUB_PACKAGE_NAME_3); + + var endpoint = withTagFilters(PROVIDER_PACKAGES + "?page=2&count=1", STUB_TAG_VALUE, STUB_TAG_VALUE_2); + var collection = getWithOk(endpoint).as(PackageCollection.class); + var packages = collection.getData(); + + assertEquals(3, (int) collection.getMeta().getTotalResults()); + assertEquals(1, packages.size()); + assertEquals(STUB_PACKAGE_NAME_2, packages.getFirst().getAttributes().getName()); + } + + @Test + void shouldReturnPackagesOnSearchByProviderIdAndAccessTypeWithPagination() { + List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.get(0).getId(), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID_4, PACKAGE, accessTypes.get(1).getId(), vertx); + + var credentialsId = configuration.getId(); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_2, STUB_VENDOR_ID, STUB_PACKAGE_NAME_2); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_3, STUB_VENDOR_ID, STUB_PACKAGE_NAME_3); + + var resourcePath = withAccessTypeFilters(PROVIDER_PACKAGES + "?page=2&count=1", + STUB_ACCESS_TYPE_NAME, STUB_ACCESS_TYPE_NAME_2); + var collection = getWithOk(resourcePath).as(PackageCollection.class); + var packages = collection.getData(); + + assertEquals(2, (int) collection.getMeta().getTotalResults()); + assertEquals(1, packages.size()); + assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getAttributes().getName()); + } + + @Test + void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByAccessType() { + var accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.getFirst().getId(), vertx); + insertAccessTypeMapping(FULL_PACKAGE_ID_4, PACKAGE, accessTypes.getFirst().getId(), vertx); + + mockGet(new RegexPattern(".*/lists/.*"), SC_INTERNAL_SERVER_ERROR); + + var endpoint = withAccessTypeFilters(PROVIDER_PACKAGES, STUB_ACCESS_TYPE_NAME); + var collection = getWithOk(endpoint).as(PackageCollection.class); + + assertEquals(2, collection.getMeta().getTotalResults()); + } + + @Test + void shouldReturnEmptyResponseWhenProvidersReturnedWithErrorOnSearchByTags() { + var credentialsId = configuration.getId(); + saveProvider(buildDbProvider(STUB_VENDOR_ID, credentialsId, STUB_VENDOR_NAME), vertx); + saveProvider(buildDbProvider(STUB_VENDOR_ID_2, credentialsId, STUB_VENDOR_NAME_2), vertx); + + saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); + saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE); + + mockGet(matching(vendorsRmApi() + ".*"), SC_INTERNAL_SERVER_ERROR); + + var endpoint = withTagFilters(PROVIDER_PATH, STUB_TAG_VALUE); + var providerCollection = getWithOk(endpoint).as(ProviderCollection.class); + + assertEquals(2, (int) providerCollection.getMeta().getTotalResults()); + } + + @Test + void shouldReturnProvidersOnSearchWithTagsAndPagination() { + saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); + saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE); + saveTag(vertx, STUB_VENDOR_ID_3, PROVIDER, STUB_TAG_VALUE); + + setUpTaggedProviders(); + + var endpoint = withTagFilters(PROVIDER_PATH + "?page=2&count=1", STUB_TAG_VALUE); + var providerCollection = getWithOk(endpoint).as(ProviderCollection.class); + var providers = providerCollection.getData(); + + assertEquals(3, (int) providerCollection.getMeta().getTotalResults()); + assertEquals(1, providers.size()); + assertEquals(STUB_VENDOR_NAME_2, providers.getFirst().getAttributes().getName()); + } + + @Test + void shouldReturnProvidersOnGetWithPackages() { + mockGet(equalTo(vendorsRmApi(STUB_VENDOR_ID)), readFile(GET_VENDOR_BY_ID_RESPONSE)); + mockGet(new RegexPattern(providerPackagesRmApi(STUB_VENDOR_ID) + ".*"), readFile(STUB_PACKAGE_RESPONSE)); + + var actualProvider = getWithOk(PROVIDER_BY_ID + "?include=packages").asString(); + + assertJsonEqual(readFile(EXPECTED_PROVIDER_WITH_PACKAGES), actualProvider); + } + + @Test + void shouldReturn500IfRmApiReturnsError() { + mockGet(equalTo(vendorsRmApi()), SC_INTERNAL_SERVER_ERROR); + + var error = getWithStatus(PROVIDER_PATH + "?q=e&count=1", SC_INTERNAL_SERVER_ERROR).as(JsonapiError.class); + + assertNotNull(error.getErrors().getFirst().getTitle()); + } + + @Test + void shouldReturnErrorIfSortParameterInvalid() { + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "?q=e&count=10&sort=abc"); + } + + @Test + void shouldReturnProviderWhenValidId() { + mockGet(equalTo(vendorsRmApi(STUB_VENDOR_ID)), readFile(GET_VENDOR_BY_ID_RESPONSE)); + + var provider = getWithOk(PROVIDER_BY_ID).asString(); + + assertJsonEqual(readFile(EXPECTED_PROVIDER), provider); + } + + @Test + void shouldReturnProviderWithTagWhenValidId() { + saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); + + mockGet(equalTo(vendorsRmApi(STUB_VENDOR_ID)), readFile(GET_VENDOR_BY_ID_RESPONSE)); + + var provider = getWithOk(PROVIDER_BY_ID).as(Provider.class); + + assertTrue(provider.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); + } + + @Test + void shouldReturn404WhenProviderIdNotFound() { + mockGet(equalTo(vendorsRmApi()), SC_NOT_FOUND); + + var error = getWithStatus(PROVIDER_PATH + "/191919", SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Provider not found"); + } + + @Test + void shouldReturn400WhenInvalidProviderId() { + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/19191919as"); + } + + @Test + void shouldUpdateAndReturnProvider() { + mockGet(equalTo(vendorsRmApi(STUB_VENDOR_ID)), readFile(GET_VENDOR_UPDATED_RESPONSE)); + mockPut(equalTo(vendorsRmApi(STUB_VENDOR_ID)), SC_NO_CONTENT); + + var provider = putWithOk(PROVIDER_BY_ID, readFile(PUT_PROVIDER)).asString(); + + assertJsonEqual(readFile(EXPECTED_UPDATED_PROVIDER), provider); + + verifyPut(equalTo(vendorsRmApi(STUB_VENDOR_ID)), equalToJson(readFile(PUT_VENDOR_TOKEN_PROXY_REQUEST)), 1); + } + + @Test + void shouldUpdateTagsOnPutTags() { + var newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); + sendPutTags(Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); + var tagsAfterRequest = getTagsForRecordType(vertx, PROVIDER); + assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); + } + + @Test + void shouldUpdateTagsOnPutTagsWithAlreadyExistingTags() { + saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); + var newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); + sendPutTags(Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); + var tagsAfterRequest = getTagsForRecordType(vertx, PROVIDER); + assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); + } + + @Test + void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() { + var tags = readJsonFile(PUT_PROVIDER_TAGS, PackageTagsPutRequest.class); + tags.getData().getAttributes().setName(""); + var error = putWithStatus(providerTagsPath(), Json.encode(tags), SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + assertErrorContainsDetail(error, "name must not be empty"); + } + + @Test + void shouldReturn400WhenRmApiErrorOnPut() { + mockPut(equalTo(vendorsRmApi(STUB_VENDOR_ID)), readFile(PUT_VENDOR_NOT_ALLOWED_RESPONSE), SC_BAD_REQUEST); + + var error = putWithStatus(PROVIDER_BY_ID, readFile(PUT_PROVIDER), SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Provider does not allow token"); + } + + @Test + void shouldReturn422WhenBodyInputInvalidOnPut() { + var providerToBeUpdated = readJsonFile(PUT_PROVIDER, ProviderPutRequest.class); + + var providerToken = new Token(); + providerToken.setValue(insecure().nextAlphanumeric(501)); + providerToBeUpdated.getData().getAttributes().setProviderToken(providerToken); + + var putBody = Json.encode(providerToBeUpdated); + var error = putWithStatus(PROVIDER_BY_ID, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid value"); + assertErrorContainsDetail(error, "Value is too long (maximum is 500 characters)"); + } + + @Test + void shouldReturnProviderPackagesWhenValidId() { + mockGet(matching(providerPackagesRmApi(STUB_VENDOR_ID) + ".*"), readFile(STUB_PACKAGE_RESPONSE)); + + var actual = getWithOk(PROVIDER_PACKAGES).asString(); + + assertJsonEqual(readFile(EXPECTED_PACKAGE_COLLECTION), actual); + } + + @Test + void shouldReturnEmptyPackageListWhenNoProviderPackagesAreFound() { + mockGet(new RegexPattern(providerPackagesRmApi(STUB_VENDOR_ID) + ".*"), readFile(GET_PACKAGES_BY_PROVIDER_EMPTY)); + + var packages = getWithOk(PROVIDER_PACKAGES).as(PackageCollection.class); + + assertTrue(packages.getData().isEmpty()); + assertEquals(0, (int) packages.getMeta().getTotalResults()); + } + + @Test + void shouldReturnProviderPackagesWithTags() { + setUpPackage(vertx, configuration.getId(), STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE_2); + + mockGet(new RegexPattern(providerPackagesRmApi(STUB_VENDOR_ID) + ".*"), readFile(STUB_PACKAGE_RESPONSE)); + + var actual = getWithOk(PROVIDER_PACKAGES).asString(); + + assertJsonEqual(readFile(EXPECTED_PACKAGE_COLLECTION_WITH_TAGS), actual); + } + + @Test + void shouldReturn400IfProviderIdInvalid() { + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/invalid/packages"); + } + + @Test + void shouldReturn400IfCountOutOfRange() { + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?count=120"); + } + + @Test + void shouldReturn400IfFilterTypeInvalid() { + checkResponseNotEmptyWhenStatusIs400( + PROVIDER_PACKAGES + "?q=Search&filter[selected]=true&filter[type]=unsupported"); + } + + @Test + void shouldReturn400IfFilterSelectedInvalid() { + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?q=Search&filter[selected]=invalid"); + } + + @Test + void shouldReturn400IfPageOffsetInvalid() { + var response = getWithStatus(PROVIDER_PACKAGES + "?q=Search&count=5&page=abc", SC_BAD_REQUEST); + assertTrue(response.response().asString().contains("For input string: \"abc\"")); + } + + @Test + void shouldReturn400IfSortInvalid() { + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?q=Search&sort=invalid"); + } + + @Test + void shouldReturn400IfQueryParamInvalid() { + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?q="); + } + + @Test + void shouldReturn404WhenNonProviderIdNotFound() { + var rmapiInvalidProviderIdUrl = RM_ACCOUNT_V2_API_PATH + "/vendors/191919/lists"; + mockGet(new RegexPattern(rmapiInvalidProviderIdUrl), SC_NOT_FOUND); + + var error = getWithStatus("/eholdings/providers/191919/packages", SC_NOT_FOUND) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Provider not found"); + } + + private String getPackageResponse(String packageName, int packageId, int providerId) { + PackageData packageData = readJsonFile(STUB_PACKAGE_JSON_PATH, PackageData.class); + return Json.encode(packageData.toBuilder() + .packageName(packageName) + .packageId(packageId) + .vendorId(providerId) + .build()); + } + + private void setUpPackages(Vertx vertx, String credentialsId) { + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_2, STUB_VENDOR_ID_2, STUB_PACKAGE_NAME_2); + setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_3, STUB_VENDOR_ID_3, STUB_PACKAGE_NAME_3); + } + + private void setUpPackage(Vertx vertx, String credentialsId, int packageId, int vendorId, String packageName) { + var dbPackage = PackagesTestUtil.buildDbPackage(vendorId + "-" + packageId, credentialsId, packageName); + PackagesTestUtil.savePackage(dbPackage, vertx); + mockPackageWithName(packageId, vendorId, packageName); + } + + private void mockPackageWithName(int stubPackageId, int stubProviderId, String stubPackageName) { + mockGet(equalTo(packageRmApi(stubPackageId)), getPackageResponse(stubPackageName, stubPackageId, stubProviderId)); + } + + private void sendPutTags(List<String> newTags) { + var tags = readJsonFile(PUT_PROVIDER_TAGS, ProviderTagsPutRequest.class); + + if (newTags != null) { + tags.getData().getAttributes().setTags(new Tags() + .withTagList(newTags)); + } + + putWithOk(providerTagsPath(), Json.encode(tags)).as(PackageTags.class); + } + + private void mockProviderWithName(int providerId, String providerName) { + var urlPattern = equalTo(vendorsRmApi(providerId)); + mockGet(urlPattern, getProviderResponse(providerName, providerId)); + } + + private String getProviderResponse(String providerName, int providerId) { + return Json.encode(VendorById.byIdBuilder() + .vendorName(providerName) + .vendorId(providerId) + .build()); + } + + private void setUpTaggedProviders() { + String credentialsId = configuration.getId(); + saveProvider(buildDbProvider(STUB_VENDOR_ID, credentialsId, STUB_VENDOR_NAME), vertx); + saveProvider(buildDbProvider(STUB_VENDOR_ID_2, credentialsId, STUB_VENDOR_NAME_2), vertx); + saveProvider(buildDbProvider(STUB_VENDOR_ID_3, credentialsId, STUB_VENDOR_NAME_3), vertx); + + mockProviderWithName(STUB_VENDOR_ID, STUB_VENDOR_NAME); + mockProviderWithName(STUB_VENDOR_ID_2, STUB_VENDOR_NAME_2); + mockProviderWithName(STUB_VENDOR_ID_3, STUB_VENDOR_NAME_3); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java new file mode 100644 index 000000000..8b6f37c4b --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java @@ -0,0 +1,158 @@ +package org.folio.rest.impl; + +import static org.folio.HttpStatus.SC_FORBIDDEN; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssertTestUtil.assertJsonEqual; +import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; + +import com.github.tomakehurst.wiremock.matching.RegexPattern; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class EholdingsProxyTypesImplIntegrationTest extends IntegrationTestBase { + + // RM API responses + private static final String GET_PROXY_TYPES_RESPONSE = + "responses/rmapi/proxytypes/get-proxy-types-response.json"; + private static final String GET_PROXY_TYPES_EMPTY_RESPONSE = + "responses/rmapi/proxytypes/get-proxy-types-empty-response.json"; + + // KB-EBSCO expected responses + private static final String EXPECTED_PROXY_TYPES_RESPONSE = + "responses/kb-ebsco/proxytypes/get-proxy-types-response.json"; + private static final String EXPECTED_PROXY_TYPES_EMPTY_RESPONSE = + "responses/kb-ebsco/proxytypes/get-proxy-types-empty-response.json"; + + private static final String PROXY_TYPES_PATH = "eholdings/proxy-types"; + private static final String PROXY_TYPES_BY_CRED_ID_PATH = "/eholdings/kb-credentials/%s/proxy-types"; + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnProxyTypesWhenUserAssignedToKbCredentials() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(proxiesRmApi()), readFile(GET_PROXY_TYPES_RESPONSE)); + + var actual = getWithStatus(PROXY_TYPES_PATH, SC_OK, JOHN_USER_ID_HEADER).asString(); + + assertJsonEqual(readFile(EXPECTED_PROXY_TYPES_RESPONSE), actual, true); + } + + @Test + void shouldReturnProxyTypesWhenOneCredentialsExistsAndUserNotAssigned() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + mockGet(new RegexPattern(proxiesRmApi()), readFile(GET_PROXY_TYPES_RESPONSE)); + + var actual = getWithStatus(PROXY_TYPES_PATH, SC_OK, JOHN_USER_ID_HEADER).asString(); + + assertJsonEqual(readFile(EXPECTED_PROXY_TYPES_RESPONSE), actual, true); + } + + @Test + void shouldReturnEmptyProxyTypesFromEmptyRmApiResponse() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(proxiesRmApi()), readFile(GET_PROXY_TYPES_EMPTY_RESPONSE)); + + var actual = getWithStatus(PROXY_TYPES_PATH, SC_OK, JOHN_USER_ID_HEADER).asString(); + + assertJsonEqual(readFile(EXPECTED_PROXY_TYPES_EMPTY_RESPONSE), actual, true); + } + + @Test + void shouldReturn404WhenUserNotAssignedToKbCredentials() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME + "1", STUB_API_KEY, "OTHER_CUSTOMER_ID", vertx); + + var error = getWithStatus(PROXY_TYPES_PATH, SC_NOT_FOUND, JANE_USER_ID_HEADER).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KB Credentials do not exist or user with userId = " + JANE_ID + + " is not assigned to any available knowledgebase."); + } + + @Test + void shouldReturn401WhenRmApiRequestCompletesWith401ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(proxiesRmApi()), SC_UNAUTHORIZED); + + var error = getWithStatus(PROXY_TYPES_PATH, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturn403WhenRmApiRequestCompletesWith403ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(proxiesRmApi()), SC_FORBIDDEN); + + var error = getWithStatus(PROXY_TYPES_PATH, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized"); + } + + @Test + void shouldReturnProxyTypesCollection() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + mockGet(new RegexPattern(proxiesRmApi()), readFile(GET_PROXY_TYPES_RESPONSE)); + + var resourcePath = String.format(PROXY_TYPES_BY_CRED_ID_PATH, STUB_CREDENTIALS_ID); + var actual = getWithOk(resourcePath).asString(); + + assertJsonEqual(readFile(EXPECTED_PROXY_TYPES_RESPONSE), actual, true); + } + + @Test + void shouldReturn401WhenRmApiReturns401ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(proxiesRmApi()), SC_UNAUTHORIZED); + + var path = String.format(PROXY_TYPES_BY_CRED_ID_PATH, STUB_CREDENTIALS_ID); + var error = getWithStatus(path, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturn403WhenRmApiReturns403ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(proxiesRmApi()), SC_FORBIDDEN); + + var path = String.format(PROXY_TYPES_BY_CRED_ID_PATH, STUB_CREDENTIALS_ID); + var error = getWithStatus(path, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized"); + } + + @Test + void shouldReturn404WhenCredentialsNotFound() { + var path = String.format(PROXY_TYPES_BY_CRED_ID_PATH, "11111111-1111-1111-a111-111111111111"); + var error = getWithStatus(path, SC_NOT_FOUND, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "KbCredentials not found by id"); + } +} + diff --git a/src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java new file mode 100644 index 000000000..9b48ea848 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java @@ -0,0 +1,622 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static java.lang.String.format; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.RecordType.RESOURCE; +import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; +import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.repository.resources.ResourceTableConstants.RESOURCES_TABLE_NAME; +import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; +import static org.folio.util.AccessTypesTestUtil.getAccessTypeMappings; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; +import static org.folio.util.AccessTypesTestUtil.testData; +import static org.folio.util.AssertTestUtil.assertEqualsResourceId; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssertTestUtil.assertJsonEqual; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.TagsTestUtil.saveTag; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.tomakehurst.wiremock.matching.EqualToJsonPattern; +import io.vertx.core.json.Json; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.folio.repository.RecordType; +import org.folio.rest.jaxrs.model.Errors; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.rest.jaxrs.model.Resource; +import org.folio.rest.jaxrs.model.ResourceBulkFetchCollection; +import org.folio.rest.jaxrs.model.ResourcePutRequest; +import org.folio.rest.jaxrs.model.ResourceTags; +import org.folio.rest.jaxrs.model.ResourceTagsPutRequest; +import org.folio.rest.jaxrs.model.Tags; +import org.folio.util.IntegrationTestBase; +import org.folio.util.ResourcesTestUtil; +import org.folio.util.TagsTestUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class EholdingsResourcesImplIntegrationTest extends IntegrationTestBase { + + // RM API response files + private static final String RMAPI_GET_RESOURCE_BY_ID_SUCCESS = + "responses/rmapi/resources/get-resource-by-id-success-response.json"; + private static final String RMAPI_GET_RESOURCE_NOT_FOUND = + "responses/rmapi/resources/get-resource-by-id-not-found-response.json"; + private static final String RMAPI_GET_RESOURCE_EMPTY_CUSTOMER_LIST = + "responses/rmapi/resources/get-resource-by-id-response-empty-customer-list.json"; + private static final String RMAPI_GET_MANAGED_RESOURCE_UPDATED = + "responses/rmapi/resources/get-managed-resource-updated-response.json"; + private static final String RMAPI_GET_MANAGED_RESOURCE_UPDATED_NOT_SELECTED = + "responses/rmapi/resources/get-managed-resource-updated-response-is-selected-false.json"; + private static final String RMAPI_GET_CUSTOM_RESOURCE_UPDATED = + "responses/rmapi/resources/get-custom-resource-updated-response.json"; + private static final String RMAPI_GET_RESOURCES_BY_PACKAGE_ID = + "responses/rmapi/resources/get-resources-by-package-id-response.json"; + private static final String RMAPI_GET_VENDOR_FOR_RESOURCE = + "responses/rmapi/vendors/get-vendor-by-id-for-resource.json"; + private static final String RMAPI_GET_PACKAGE_FOR_RESOURCE = + "responses/rmapi/packages/get-package-by-id-for-resource.json"; + private static final String RMAPI_GET_CUSTOM_PACKAGE = + "responses/rmapi/packages/get-custom-package-by-id-response.json"; + + // KB-EBSCO expected response files + private static final String EXPECTED_RESOURCE_BY_ID = + "responses/kb-ebsco/resources/expected-resource-by-id.json"; + private static final String EXPECTED_RESOURCE_WITH_TITLE = + "responses/kb-ebsco/resources/expected-resource-by-id-with-title.json"; + private static final String EXPECTED_RESOURCE_WITH_PROVIDER = + "responses/kb-ebsco/resources/expected-resource-by-id-with-provider.json"; + private static final String EXPECTED_RESOURCE_WITH_PACKAGE = + "responses/kb-ebsco/resources/expected-resource-by-id-with-package.json"; + private static final String EXPECTED_RESOURCE_WITH_ALL_OBJECTS = + "responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json"; + private static final String EXPECTED_MANAGED_RESOURCE = + "responses/kb-ebsco/resources/expected-managed-resource.json"; + private static final String EXPECTED_CUSTOM_RESOURCE = + "responses/kb-ebsco/resources/expected-custom-resource.json"; + private static final String EXPECTED_RESOURCE_WITH_ACCESS_TYPE = + "responses/kb-ebsco/resources/expected-resource-by-id-with-access-type.json"; + private static final String EXPECTED_RESOURCE_AFTER_POST = + "responses/kb-ebsco/resources/expected-resource-after-post.json"; + private static final String EXPECTED_RESOURCES_BULK_RESPONSE = + "responses/kb-ebsco/resources/expected-resources-bulk-response.json"; + private static final String EXPECTED_RESOURCES_BULK_WITH_FAILED_IDS = + "responses/kb-ebsco/resources/expected-resources-bulk-response-with-failed-ids.json"; + private static final String EXPECTED_RESPONSE_TOO_LONG_ID = + "responses/kb-ebsco/resources/expected-response-on-too-long-id.json"; + + // Request payload files + private static final String REQUEST_PUT_MANAGED_RESOURCE = + "requests/kb-ebsco/resource/put-managed-resource.json"; + private static final String REQUEST_PUT_MANAGED_RESOURCE_NOT_SELECTED = + "requests/kb-ebsco/resource/put-managed-resource-is-not-selected.json"; + private static final String REQUEST_PUT_MANAGED_RESOURCE_MISSING_ACCESS_TYPE = + "requests/kb-ebsco/resource/put-managed-resource-with-missing-access-type.json"; + private static final String REQUEST_PUT_MANAGED_RESOURCE_INVALID_ACCESS_TYPE = + "requests/kb-ebsco/resource/put-managed-resource-with-invalid-access-type.json"; + private static final String REQUEST_PUT_RESOURCE_WITH_ACCESS_TYPE = + "requests/kb-ebsco/resource/put-resource-with-access-type.json"; + private static final String REQUEST_PUT_CUSTOM_RESOURCE = + "requests/kb-ebsco/resource/put-custom-resource.json"; + private static final String REQUEST_PUT_CUSTOM_RESOURCE_WITH_PROXIED_URL = + "requests/kb-ebsco/resource/put-custom-resource-with-proxied-url.json"; + private static final String REQUEST_PUT_CUSTOM_RESOURCE_INVALID_URL = + "requests/kb-ebsco/resource/put-custom-resource-invalid-url.json"; + private static final String REQUEST_PUT_RESOURCE_TAGS = + "requests/kb-ebsco/resource/put-resource-tags.json"; + private static final String REQUEST_POST_RESOURCES = + "requests/kb-ebsco/resource/post-resources-request.json"; + private static final String REQUEST_POST_RESOURCES_BULK = + "requests/kb-ebsco/resource/post-resources-bulk.json"; + private static final String REQUEST_POST_RESOURCES_BULK_INVALID_FORMAT = + "requests/kb-ebsco/resource/post-resources-bulk-with-invalid-id-format.json"; + private static final String REQUEST_POST_RESOURCES_BULK_INVALID_IDS = + "requests/kb-ebsco/resource/post-resources-bulk-with-invalid-ids.json"; + private static final String REQUEST_POST_RESOURCE_TOO_LONG_ID = + "requests/kb-ebsco/resource/post-resource-with-too-long-id.json"; + + // RM API request files + private static final String RMAPI_PUT_MANAGED_RESOURCE_IS_SELECTED = + "requests/rmapi/resources/put-managed-resource-is-selected-multiple-attributes.json"; + private static final String RMAPI_PUT_MANAGED_RESOURCE_NOT_SELECTED = + "requests/rmapi/resources/put-managed-resource-is-not-selected.json"; + private static final String RMAPI_PUT_CUSTOM_RESOURCE_IS_SELECTED = + "requests/rmapi/resources/put-custom-resource-is-selected-multiple-attributes.json"; + private static final String RMAPI_SELECT_RESOURCE_REQUEST = + "requests/rmapi/resources/select-resource-request.json"; + + // API endpoint paths + private static final String RESOURCES_PATH = "eholdings/resources"; + private static final String RESOURCE_BY_ID_PATH = RESOURCES_PATH + "/%s"; + private static final String STUB_MANAGED_RESOURCE_PATH = RESOURCE_BY_ID_PATH.formatted(STUB_MANAGED_RESOURCE_ID); + private static final String RESOURCE_TAGS_PATH = RESOURCE_BY_ID_PATH.formatted(STUB_CUSTOM_RESOURCE_ID) + "/tags"; + private static final String RESOURCES_BULK_FETCH = RESOURCES_PATH + "/bulk/fetch"; + + private String credentialsId; + + @BeforeEach + void setUp() { + credentialsId = setupDefaultKbConfiguration(getWiremockUrl(), vertx); + } + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); + clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); + clearDataFromTable(vertx, TAGS_TABLE_NAME); + clearDataFromTable(vertx, RESOURCES_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnResourceWhenValidId() { + mockResource(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + + var actualResponse = getWithOk(STUB_MANAGED_RESOURCE_PATH).asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCE_BY_ID), actualResponse, true); + } + + @Test + void shouldReturnResourceWithTags() { + saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); + mockResource(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + + var resource = getWithOk(STUB_MANAGED_RESOURCE_PATH).as(Resource.class); + + assertTrue(resource.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); + } + + @Test + void shouldReturnResourceWithTitleWhenTitleFlagSetToTrue() { + mockResource(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + + var actualResponse = + getWithOk(withInclude(RESOURCE_BY_ID_PATH.formatted(STUB_MANAGED_RESOURCE_ID), "title")).asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCE_WITH_TITLE), actualResponse, true); + } + + @Test + void shouldReturnResourceWithProviderWhenProviderFlagSetToTrue() { + mockResource(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + mockVendor(RMAPI_GET_VENDOR_FOR_RESOURCE); + + var actualResponse = + getWithOk(withInclude(RESOURCE_BY_ID_PATH.formatted(STUB_MANAGED_RESOURCE_ID), "provider")).asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCE_WITH_PROVIDER), actualResponse, true); + } + + @Test + void shouldReturnResourceWithPackageWhenPackageFlagSetToTrue() { + mockResource(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + mockPackage(RMAPI_GET_PACKAGE_FOR_RESOURCE); + + var actualResponse = + getWithOk(withInclude(RESOURCE_BY_ID_PATH.formatted(STUB_MANAGED_RESOURCE_ID), "package")).asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCE_WITH_PACKAGE), actualResponse, true); + } + + @Test + void shouldReturnResourceWithAllIncludedObjectsWhenIncludeContainsAllObjects() { + mockResource(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + mockVendor(RMAPI_GET_VENDOR_FOR_RESOURCE); + mockPackage(RMAPI_GET_PACKAGE_FOR_RESOURCE); + + var actualResponse = getWithOk( + withInclude(RESOURCE_BY_ID_PATH.formatted(STUB_MANAGED_RESOURCE_ID), "package", "title", "provider")).asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCE_WITH_ALL_OBJECTS), actualResponse, true); + } + + @Test + void shouldReturn404WhenRmApiNotFoundOnResourceGet() { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), + readFile(RMAPI_GET_RESOURCE_NOT_FOUND), SC_NOT_FOUND); + + var error = getWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Title is no longer in this package."); + } + + @Test + void shouldReturn404WhenCustomerListIsEmpty() { + mockResource(RMAPI_GET_RESOURCE_EMPTY_CUSTOMER_LIST); + + var error = getWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Title is no longer in this package"); + } + + @Test + void shouldReturn400WhenValidationErrorOnResourceGet() { + var error = getWithStatus(RESOURCE_BY_ID_PATH.formatted("583-abc-762169"), SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Resource id is invalid - 583-abc-762169"); + } + + @Test + void shouldReturn500WhenRmApiReturns500ErrorOnResourceGet() { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), SC_INTERNAL_SERVER_ERROR); + + var error = getWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_INTERNAL_SERVER_ERROR) + .as(JsonapiError.class); + + assertNotNull(error.getErrors().getFirst().getTitle()); + } + + @Test + void shouldReturnUpdatedValuesManagedResourceOnSuccessfulPut() { + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + var actualResponse = mockUpdateResourceScenario(RMAPI_GET_MANAGED_RESOURCE_UPDATED, + managedResourceEndpoint, STUB_MANAGED_RESOURCE_ID, readFile(REQUEST_PUT_MANAGED_RESOURCE)); + + assertJsonEqual(readFile(EXPECTED_MANAGED_RESOURCE), actualResponse, false); + + verifyPut(matching(managedResourceEndpoint), equalToJson(readFile(RMAPI_PUT_MANAGED_RESOURCE_IS_SELECTED))); + } + + @Test + void shouldCreateNewAccessTypeMappingOnSuccessfulPut() { + var accessTypes = insertAccessTypes(testData(credentialsId), vertx); + var accessTypeId = accessTypes.getFirst().getId(); + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + var requestBody = format(readFile(REQUEST_PUT_RESOURCE_WITH_ACCESS_TYPE), accessTypeId); + var actualResponse = mockUpdateResourceScenario(RMAPI_GET_MANAGED_RESOURCE_UPDATED, + managedResourceEndpoint, STUB_MANAGED_RESOURCE_ID, requestBody); + + var expectedJson = format(readFile(EXPECTED_RESOURCE_WITH_ACCESS_TYPE), accessTypeId, accessTypeId); + assertJsonEqual(expectedJson, actualResponse, false); + + verifyPut(matching(managedResourceEndpoint), equalToJson(readFile(RMAPI_PUT_MANAGED_RESOURCE_IS_SELECTED))); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(1, accessTypeMappingsInDb.size()); + assertEquals(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId().toString()); + assertEquals(RESOURCE, accessTypeMappingsInDb.getFirst().getRecordType()); + } + + @Test + void shouldDeleteAccessTypeMappingOnSuccessfulPut() { + var accessTypes = insertAccessTypes(testData(credentialsId), vertx); + var accessTypeId = accessTypes.getFirst().getId(); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypeId, vertx); + + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + var actualResponse = mockUpdateResourceScenario(RMAPI_GET_MANAGED_RESOURCE_UPDATED, + managedResourceEndpoint, STUB_MANAGED_RESOURCE_ID, readFile(REQUEST_PUT_MANAGED_RESOURCE)); + + assertJsonEqual(readFile(EXPECTED_MANAGED_RESOURCE), actualResponse, false); + + verifyPut(matching(managedResourceEndpoint), equalToJson(readFile(RMAPI_PUT_MANAGED_RESOURCE_IS_SELECTED))); + + var accessTypeMappingsInDb = getAccessTypeMappings(vertx); + assertEquals(0, accessTypeMappingsInDb.size()); + } + + @Test + void shouldReturn400OnPutPackageWithNotExistedAccessType() { + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + var error = putWithStatus(STUB_MANAGED_RESOURCE_PATH, readFile(REQUEST_PUT_MANAGED_RESOURCE_MISSING_ACCESS_TYPE), + SC_BAD_REQUEST, CONTENT_TYPE_HEADER).as(JsonapiError.class); + + verifyPut(matching(managedResourceEndpoint), 0); + + assertErrorContainsTitle(error, "Access type not found: id = 99999999-9999-1999-a999-999999999999"); + } + + @Test + void shouldReturn422OnPutPackageWithInvalidAccessTypeId() { + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + var error = putWithStatus(STUB_MANAGED_RESOURCE_PATH, readFile(REQUEST_PUT_MANAGED_RESOURCE_INVALID_ACCESS_TYPE), + SC_UNPROCESSABLE_CONTENT, CONTENT_TYPE_HEADER).as(Errors.class); + + verifyPut(matching(managedResourceEndpoint), 0); + + assertEquals(1, error.getErrors().size()); + assertEquals( + "must match \"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[1-5][a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$\"", + error.getErrors().getFirst().getMessage()); + } + + @Test + void shouldDeselectManagedResourceOnPutWithSelectedFalse() { + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + var request = readJsonFile(REQUEST_PUT_MANAGED_RESOURCE_NOT_SELECTED, ResourcePutRequest.class); + request.getData().getAttributes().setIsSelected(false); + var actualResponse = mockUpdateResourceScenario(RMAPI_GET_MANAGED_RESOURCE_UPDATED_NOT_SELECTED, + managedResourceEndpoint, STUB_MANAGED_RESOURCE_ID, Json.encode(request)); + + var expectedResource = readJsonFile(EXPECTED_MANAGED_RESOURCE, Resource.class); + expectedResource.getData().getAttributes().setIsSelected(false); + assertJsonEqual(Json.encode(expectedResource), actualResponse, false); + + verifyPut(matching(managedResourceEndpoint), + new EqualToJsonPattern(readFile(RMAPI_PUT_MANAGED_RESOURCE_NOT_SELECTED), true, true)); + } + + @Test + void shouldReturnUpdatedValuesCustomResourceOnSuccessfulPut() { + var customResourceEndpoint = resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID); + + var actualResponse = mockUpdateResourceScenario(RMAPI_GET_CUSTOM_RESOURCE_UPDATED, + customResourceEndpoint, STUB_CUSTOM_RESOURCE_ID, readFile(REQUEST_PUT_CUSTOM_RESOURCE)); + + assertJsonEqual(readFile(EXPECTED_CUSTOM_RESOURCE), actualResponse, false); + + verifyPut(matching(customResourceEndpoint), equalToJson(readFile(RMAPI_PUT_CUSTOM_RESOURCE_IS_SELECTED))); + } + + @Test + void shouldAcceptValuesCustomResourceWithUnrecognizedFieldInProxy() { + var customResourceEndpoint = resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID); + + var actualResponse = mockUpdateResourceScenario(RMAPI_GET_CUSTOM_RESOURCE_UPDATED, + customResourceEndpoint, STUB_CUSTOM_RESOURCE_ID, readFile(REQUEST_PUT_CUSTOM_RESOURCE_WITH_PROXIED_URL)); + + assertJsonEqual(readFile(EXPECTED_CUSTOM_RESOURCE), actualResponse, false); + + verifyPut(matching(customResourceEndpoint), equalToJson(readFile(RMAPI_PUT_CUSTOM_RESOURCE_IS_SELECTED))); + } + + @Test + void shouldUpdateTagsOnSuccessfulTagsPut() { + sendPutTags(Collections.singletonList(STUB_TAG_VALUE)); + + var resources = ResourcesTestUtil.getResources(vertx); + assertEquals(1, resources.size()); + assertEqualsResourceId(resources.getFirst().getId()); + assertEquals(STUB_VENDOR_NAME, resources.getFirst().getName()); + } + + @Test + void shouldUpdateTagsOnSuccessfulTagsPutWithAlreadyExistingTags() { + saveTag(vertx, STUB_CUSTOM_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); + var newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); + sendPutTags(newTags); + + var tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, RecordType.RESOURCE); + assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); + } + + @Test + void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() { + var tags = readJsonFile(REQUEST_PUT_RESOURCE_TAGS, ResourceTagsPutRequest.class); + tags.getData().getAttributes().setName(""); + + var error = putWithStatus(RESOURCE_TAGS_PATH, Json.encode(tags), SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid name"); + } + + @Test + void shouldReturn422WhenInvalidUrlIsProvidedForCustomResource() { + var customResourceEndpoint = resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID); + + mockGet(matching(customResourceEndpoint), readFile(RMAPI_GET_CUSTOM_RESOURCE_UPDATED)); + + var error = putWithStatus(RESOURCE_BY_ID_PATH.formatted(STUB_CUSTOM_RESOURCE_ID), + readFile(REQUEST_PUT_CUSTOM_RESOURCE_INVALID_URL), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid url"); + } + + @Test + void shouldPostResourceToRmApi() { + mockPackageResources(RMAPI_GET_RESOURCES_BY_PACKAGE_ID); + mockPackage(RMAPI_GET_CUSTOM_PACKAGE); + mockTitle(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + mockResource(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + var putRequestBodyPattern = new EqualToJsonPattern(readFile(RMAPI_SELECT_RESOURCE_REQUEST), true, true); + mockPut(matching(managedResourceEndpoint), putRequestBodyPattern, SC_NO_CONTENT); + + var actualResponse = postWithOk(RESOURCES_PATH, readFile(REQUEST_POST_RESOURCES)) + .asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCE_AFTER_POST), actualResponse, true); + + verifyPut(equalTo(managedResourceEndpoint), putRequestBodyPattern); + } + + @Test + void shouldReturn404IfTitleOrPackageIsNotFound() { + mockGet(matching(titlesRmApi() + ".*"), SC_NOT_FOUND); + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), SC_NOT_FOUND); + + var error = postWithStatus(RESOURCES_PATH, readFile(REQUEST_POST_RESOURCES), SC_NOT_FOUND).as(JsonapiError.class); + + assertErrorContainsTitle(error, "not found"); + } + + @Test + void shouldReturn422IfPackageIsNotCustom() { + mockPackageResources(RMAPI_GET_RESOURCES_BY_PACKAGE_ID); + mockPackage(RMAPI_GET_PACKAGE_FOR_RESOURCE); + mockTitle(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); + + var error = + postWithStatus(RESOURCES_PATH, readFile(REQUEST_POST_RESOURCES), SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); + + assertTrue(error.getErrors().getFirst().getTitle().contains("Invalid PackageId")); + } + + @Test + void shouldSendDeleteRequestForResourceAssociatedWithCustomPackage() { + var putBodyPattern = new EqualToJsonPattern("{\"isSelected\":false}", true, true); + var customResourceEndpoint = resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID); + deleteResource(putBodyPattern); + + verifyPut(equalTo(customResourceEndpoint), putBodyPattern); + } + + @Test + void shouldDeleteTagsOnDeleteRequest() { + saveTag(vertx, STUB_CUSTOM_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); + deleteResource(new EqualToJsonPattern("{\"isSelected\":false}", true, true)); + + var actualTags = TagsTestUtil.getTags(vertx); + assertTrue(actualTags.isEmpty()); + } + + @Test + void shouldDeleteAccessTypeOnDeleteRequest() { + var accessTypeId = insertAccessTypes(testData(credentialsId), vertx).getFirst().getId(); + insertAccessTypeMapping(STUB_CUSTOM_RESOURCE_ID, RecordType.RESOURCE, accessTypeId, vertx); + deleteResource(new EqualToJsonPattern("{\"isSelected\":false}", true, true)); + + var actualMappings = getAccessTypeMappings(vertx); + assertTrue(actualMappings.isEmpty()); + } + + @Test + void shouldReturn400WhenResourceIdIsInvalid() { + var error = deleteWithStatus(RESOURCE_BY_ID_PATH.formatted("abc-def"), SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Resource id is invalid"); + } + + @Test + void shouldReturn400WhenTryingToDeleteResourceAssociatedWithManagedPackage() { + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + mockGet(equalTo(managedResourceEndpoint), readFile(RMAPI_GET_MANAGED_RESOURCE_UPDATED)); + + var error = deleteWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Resource cannot be deleted"); + } + + @Test + void shouldReturnListWithBulkFetchResources() { + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + + mockGet(equalTo(managedResourceEndpoint), readFile(RMAPI_GET_RESOURCE_BY_ID_SUCCESS)); + + var postBody = readFile(REQUEST_POST_RESOURCES_BULK); + var actualResponse = postWithOk(RESOURCES_BULK_FETCH, postBody).asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCES_BULK_RESPONSE), actualResponse, true); + } + + @Test + void shouldReturn422OnInvalidIdFormat() { + var error = postWithStatus(RESOURCES_BULK_FETCH, readFile(REQUEST_POST_RESOURCES_BULK_INVALID_FORMAT), + SC_UNPROCESSABLE_CONTENT).as(Errors.class); + + assertEquals("elements in list must match pattern", error.getErrors().getFirst().getMessage()); + } + + @Test + void shouldReturnResponseWhenIdIsTooLong() { + var actualResponse = postWithOk(RESOURCES_BULK_FETCH, readFile(REQUEST_POST_RESOURCE_TOO_LONG_ID)).asString(); + + assertJsonEqual(readFile(EXPECTED_RESPONSE_TOO_LONG_ID), actualResponse, false); + } + + @Test + void shouldReturnResourcesAndFailedIds() { + var managedResourceEndpoint = resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID); + var customResourceEndpoint = resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID); + var thirdResourceEndpoint = resourcesRmApi(186, 3150130, 19087948); + + mockGet(equalTo(managedResourceEndpoint), readFile(RMAPI_GET_RESOURCE_BY_ID_SUCCESS)); + mockGet(equalTo(customResourceEndpoint), readFile(RMAPI_GET_CUSTOM_RESOURCE_UPDATED)); + mockGet(equalTo(thirdResourceEndpoint), readFile(RMAPI_GET_RESOURCE_NOT_FOUND), SC_NOT_FOUND); + + var actualResponse = postWithOk(RESOURCES_BULK_FETCH, readFile(REQUEST_POST_RESOURCES_BULK_INVALID_IDS)).asString(); + + assertJsonEqual(readFile(EXPECTED_RESOURCES_BULK_WITH_FAILED_IDS), actualResponse, false); + } + + @Test + void shouldReturnErrorWhenRmApiFails() { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), SC_INTERNAL_SERVER_ERROR); + + var bulkFetchCollection = postWithOk(RESOURCES_BULK_FETCH, readFile(REQUEST_POST_RESOURCES_BULK)) + .as(ResourceBulkFetchCollection.class); + + assertEquals(0, bulkFetchCollection.getIncluded().size()); + assertEquals(1, bulkFetchCollection.getMeta().getFailed().getResources().size()); + assertEquals(STUB_MANAGED_RESOURCE_ID, bulkFetchCollection.getMeta().getFailed().getResources().getFirst()); + } + + private void mockPackageResources(String responseFile) { + mockGet(matching(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID) + ".*"), readFile(responseFile)); + } + + private void mockPackage(String responseFile) { + mockGet(matching(packageRmApi(STUB_PACKAGE_ID)), readFile(responseFile)); + } + + private void mockResource(String responseFile) { + mockGet(matching(resourcesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_MANAGED_TITLE_ID)), + readFile(responseFile)); + } + + private void mockTitle(String responseFile) { + mockGet(matching(titlesRmApi() + ".*"), readFile(responseFile)); + } + + private void mockVendor(String responseFile) { + mockGet(matching(vendorsRmApi(STUB_VENDOR_ID)), readFile(responseFile)); + } + + private String mockUpdateResourceScenario(String updatedResourceResponseFile, String resourceEndpoint, + String resourceId, String requestBody) { + mockGet(matching(resourceEndpoint), readFile(updatedResourceResponseFile)); + mockPut(matching(resourceEndpoint), SC_NO_CONTENT); + return putWithOk(RESOURCE_BY_ID_PATH.formatted(resourceId), requestBody).asString(); + } + + private void sendPutTags(List<String> newTags) { + var tags = readJsonFile(REQUEST_PUT_RESOURCE_TAGS, ResourceTagsPutRequest.class); + + if (newTags != null) { + tags.getData().getAttributes().setTags(new Tags().withTagList(newTags)); + } + + putWithOk(RESOURCE_TAGS_PATH, Json.encode(tags)).as(ResourceTags.class); + } + + private void deleteResource(EqualToJsonPattern putBodyPattern) { + var customResourceEndpoint = resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID); + + mockGet(equalTo(customResourceEndpoint), readFile(RMAPI_GET_CUSTOM_RESOURCE_UPDATED)); + mockPut(equalTo(customResourceEndpoint), putBodyPattern, SC_NO_CONTENT); + + deleteWithNoContent(RESOURCE_BY_ID_PATH.formatted(STUB_CUSTOM_RESOURCE_ID)); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java new file mode 100644 index 000000000..8577996ea --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java @@ -0,0 +1,216 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_FORBIDDEN; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssertTestUtil.assertJsonEqual; +import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; + +import com.github.tomakehurst.wiremock.matching.EqualToPattern; +import com.github.tomakehurst.wiremock.matching.RegexPattern; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class EholdingsRootProxyImplIntegrationTest extends IntegrationTestBase { + + private static final String EHOLDINGS_ROOT_PROXY_URL = "eholdings/root-proxy"; + private static final String EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL = "/eholdings/kb-credentials/%s/root-proxy"; + + // RM API responses + private static final String RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE = + "responses/rmapi/proxiescustomlabels/get-success-response.json"; + private static final String RMAPI_ROOT_PROXY_UPDATED_RESPONSE = + "responses/rmapi/proxiescustomlabels/get-updated-response.json"; + private static final String RMAPI_ROOT_PROXY_400_ERROR_RESPONSE = + "responses/rmapi/proxiescustomlabels/put-400-error-response.json"; + + // KB-EBSCO expected responses + private static final String KB_EBSCO_GET_ROOT_PROXY_RESPONSE = + "responses/kb-ebsco/root-proxy/get-root-proxy-response.json"; + private static final String KB_EBSCO_PUT_ROOT_PROXY_UPDATED_RESPONSE = + "responses/kb-ebsco/root-proxy/put-root-proxy-response-updated.json"; + + // Request payloads + private static final String KB_EBSCO_PUT_ROOT_PROXY_REQUEST = + "requests/kb-ebsco/put-root-proxy.json"; + private static final String RMAPI_PUT_ROOT_PROXY_REQUEST = + "requests/rmapi/proxiescustomlabels/put-root-proxy.json"; + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnRootProxyWhenUserAssignedToKbCredentials() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), readFile(RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE)); + + var actual = getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_OK, JOHN_USER_ID_HEADER).asString(); + + var expected = readFile(KB_EBSCO_GET_ROOT_PROXY_RESPONSE); + assertJsonEqual(expected, actual, true); + } + + @Test + void shouldReturnRootProxyWhenOneCredentialsExistsAndUserNotAssigned() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), readFile(RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE)); + + var actual = getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_OK, JOHN_USER_ID_HEADER).asString(); + + var expected = readFile(KB_EBSCO_GET_ROOT_PROXY_RESPONSE); + assertJsonEqual(expected, actual, true); + } + + @Test + void shouldReturn404WhenUserNotAssignedToKbCredentials() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + saveKbCredentials(getWiremockUrl(), CREDENTIALS_NAME + "1", STUB_API_KEY, "OTHER_CUSTOMER_ID", vertx); + + var error = getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_NOT_FOUND, JANE_USER_ID_HEADER).as(JsonapiError.class); + + assertErrorContainsTitle(error, "KB Credentials do not exist or user with userId = " + JANE_ID + + " is not assigned to any available knowledgebase."); + } + + @Test + void shouldReturn401WhenRmApiRequestCompletesWith401ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_UNAUTHORIZED); + var error = getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturn403WhenRmApiRequestCompletesWith403ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_FORBIDDEN); + var error = getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized"); + } + + @Test + void shouldReturnRootProxyWhenUserAssignedToCredentials() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), readFile(RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE)); + + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var actual = getWithStatus(path, SC_OK, JOHN_USER_ID_HEADER).asString(); + + var expected = readFile(KB_EBSCO_GET_ROOT_PROXY_RESPONSE); + assertJsonEqual(expected, actual, true); + } + + @Test + void shouldReturn401WhenRmApiReturns401ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_UNAUTHORIZED); + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var error = getWithStatus(path, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturn403WhenRmApiReturns403ErrorStatus() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_FORBIDDEN); + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var error = getWithStatus(path, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized"); + } + + @Test + void shouldReturn404WhenCredentialsNotFound() { + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, "11111111-1111-1111-a111-111111111111"); + var error = getWithStatus(path, SC_NOT_FOUND, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "KbCredentials not found by id"); + } + + @Test + void shouldReturnUpdatedProxyOnSuccessfulPut() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), readFile(RMAPI_ROOT_PROXY_UPDATED_RESPONSE)); + mockPut(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_NO_CONTENT); + + var expected = readFile(KB_EBSCO_PUT_ROOT_PROXY_UPDATED_RESPONSE); + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var actual = putWithOk(path, readFile(KB_EBSCO_PUT_ROOT_PROXY_REQUEST)).asString(); + + assertJsonEqual(expected, actual, true); + + verifyPut(matching(rootProxyCustomLabelsRmApi()), equalToJson(readFile(RMAPI_PUT_ROOT_PROXY_REQUEST))); + } + + @Test + void shouldReturn400WhenInvalidProxyIdAndRmApiErrorOnPut() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + mockGet(new EqualToPattern(rootProxyCustomLabelsRmApi()), readFile(RMAPI_ROOT_PROXY_UPDATED_RESPONSE)); + mockPut(new EqualToPattern(rootProxyCustomLabelsRmApi()), readFile(RMAPI_ROOT_PROXY_400_ERROR_RESPONSE), + SC_BAD_REQUEST); + + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var error = putWithStatus(path, readFile(KB_EBSCO_PUT_ROOT_PROXY_REQUEST), SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid Proxy ID"); + } + + @Test + void shouldReturnNotFoundWhenNoKbCredentialsStored() { + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var error = putWithStatus(path, readFile(KB_EBSCO_PUT_ROOT_PROXY_REQUEST), SC_NOT_FOUND).as(JsonapiError.class); + assertErrorContainsTitle(error, "KbCredentials not found by id"); + } + + @Test + void shouldReturn401WhenRmApiReturns401() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_UNAUTHORIZED); + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var error = getWithStatus(path, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized Access"); + } + + @Test + void shouldReturn403WhenRmApiReturns403() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + + mockGet(new RegexPattern(rootProxyCustomLabelsRmApi()), SC_FORBIDDEN); + var path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); + var error = getWithStatus(path, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); + assertErrorContainsTitle(error, "Unauthorized"); + } +} + diff --git a/src/test/java/org/folio/rest/impl/EholdingsStatusIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsStatusIntegrationTest.java new file mode 100644 index 000000000..ce5724b9f --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsStatusIntegrationTest.java @@ -0,0 +1,90 @@ +package org.folio.rest.impl; + +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TOKEN; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.github.tomakehurst.wiremock.matching.RegexPattern; +import io.restassured.RestAssured; +import org.folio.okapi.common.XOkapiHeaders; +import org.folio.rest.jaxrs.model.ConfigurationStatus; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.util.AssertTestUtil; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class EholdingsStatusIntegrationTest extends IntegrationTestBase { + + private static final String EHOLDINGS_STATUS_PATH = "eholdings/status"; + + // RM API responses + private static final String GET_ZERO_VENDORS_RESPONSE = "responses/rmapi/vendors/get-zero-vendors-response.json"; + + // Request/response bodies + private static final String TOO_MANY_REQUESTS_BODY = """ + { + "Errors": [ + { + "Code": 1010, + "Message": "Too Many Requests.", + "SubCode": 0 + } + ] + }"""; + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnTrueWhenRmApiRequestCompletesWith200Status() { + setupDefaultKbConfiguration(getWiremockUrl(), vertx); + mockGet(new RegexPattern(RM_ACCOUNTS_ANY_PATH_REGEX), readFile(GET_ZERO_VENDORS_RESPONSE)); + + var status = getWithOk(EHOLDINGS_STATUS_PATH).as(ConfigurationStatus.class); + assertEquals(true, status.getData().getAttributes().getIsConfigurationValid()); + } + + @Test + void shouldReturnFalseWhenRmApiRequestCompletesWithErrorStatus() { + setupDefaultKbConfiguration(getWiremockUrl(), vertx); + mockGet(new RegexPattern(RM_ACCOUNTS_ANY_PATH_REGEX), 401); + + var status = getWithOk(EHOLDINGS_STATUS_PATH).as(ConfigurationStatus.class); + assertEquals(false, status.getData().getAttributes().getIsConfigurationValid()); + } + + @Test + void shouldReturnErrorWhenRmApiRequestCompletesWith429() { + setupDefaultKbConfiguration(getWiremockUrl(), vertx); + mockGet(new RegexPattern(RM_ACCOUNTS_ANY_PATH_REGEX), TOO_MANY_REQUESTS_BODY, 429); + + var error = getWithStatus(EHOLDINGS_STATUS_PATH, 429).as(JsonapiError.class); + AssertTestUtil.assertErrorContainsTitle(error, "Too Many Requests"); + } + + @Test + void shouldReturn500OnInvalidOkapiUrl() { + RestAssured.given() + .header(XOkapiHeaders.TENANT, STUB_TENANT) + .header(XOkapiHeaders.TOKEN, STUB_TOKEN) + .header(XOkapiHeaders.URL, "wrongUrl^") + .baseUri(moduleUrl) + .when() + .get(EHOLDINGS_STATUS_PATH) + .then() + .statusCode(500); + } + + @Test + void shouldReturnFalseIfEmptyConfig() { + var status = getWithOk(EHOLDINGS_STATUS_PATH).as(ConfigurationStatus.class); + assertEquals(false, status.getData().getAttributes().getIsConfigurationValid()); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java new file mode 100644 index 000000000..76b560f49 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java @@ -0,0 +1,201 @@ +package org.folio.rest.impl; + +import static java.util.Arrays.asList; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.common.ListUtils.mapItems; +import static org.folio.repository.RecordType.PACKAGE; +import static org.folio.repository.RecordType.PROVIDER; +import static org.folio.repository.RecordType.RESOURCE; +import static org.folio.repository.RecordType.TITLE; +import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.TagsTestUtil.buildTag; +import static org.folio.util.TagsTestUtil.saveTags; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Predicate; +import org.apache.commons.collections4.CollectionUtils; +import org.folio.repository.tag.DbTag; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.rest.jaxrs.model.MetaTotalResults; +import org.folio.rest.jaxrs.model.TagCollection; +import org.folio.rest.jaxrs.model.TagCollectionItem; +import org.folio.rest.jaxrs.model.TagUniqueCollection; +import org.folio.rest.util.RestConstants; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.converter.Converter; + +class EholdingsTagsImplIntegrationTest extends IntegrationTestBase { + + private static final DbTag PACKAGE_TAG = buildTag(FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); + private static final DbTag RESOURCE_TAG = buildTag(STUB_MANAGED_RESOURCE_ID, RESOURCE, STUB_TAG_VALUE_2); + private static final DbTag PROVIDER_TAG = buildTag(STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE_3); + private static final DbTag TITLE_TAG = buildTag(STUB_TITLE_ID, TITLE, STUB_TAG_VALUE_4); + private static final List<DbTag> ALL_TAGS = asList(PROVIDER_TAG, PACKAGE_TAG, TITLE_TAG, RESOURCE_TAG); + private static final List<DbTag> UNIQUE_TAGS = asList(PROVIDER_TAG, PACKAGE_TAG, PACKAGE_TAG, TITLE_TAG, RESOURCE_TAG, + RESOURCE_TAG); + private static final String TAGS_PATH = "eholdings/tags"; + + @Autowired + private Converter<DbTag, TagCollectionItem> tagConverter; + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, TAGS_TABLE_NAME); + } + + @Test + void shouldReturnAllTagsSortedIfNotFilteredOnGet() { + var tags = saveTags(ALL_TAGS, vertx); + + var col = getWithOk(TAGS_PATH).as(TagCollection.class); + + var expected = buildTagCollection(tags); + assertEquals(expected, col); + } + + @Test + void shouldReturnEmptyCollectionIfNoTagsOnGet() { + var col = getWithOk(TAGS_PATH).as(TagCollection.class); + + var expected = buildTagCollection(Collections.emptyList()); + assertEquals(expected, col); + } + + @Test + void shouldFilterByRecordTypeOnGet() { + var tags = saveTags(ALL_TAGS, vertx); + + var col = getWithOk(TAGS_PATH + "?filter[rectype]=provider").as(TagCollection.class); + + var expected = buildTagCollection(filter(tags, similarTo(PROVIDER_TAG))); + assertEquals(expected, col); + } + + @Test + void shouldFilterBySeveralRecordTypesOnGet() { + var tags = saveTags(ALL_TAGS, vertx); + + var col = getWithOk(TAGS_PATH + "?filter[rectype]=provider&filter[rectype]=title").as( + TagCollection.class); + + var expected = buildTagCollection(filter(tags, similarTo(PROVIDER_TAG).or(similarTo(TITLE_TAG)))); + assertEquals(expected, col); + } + + @Test + void shouldReturnEmptyCollectionIfFilteredOutOnGet() { + saveTags(asList(PROVIDER_TAG, PACKAGE_TAG), vertx); + + var col = getWithOk(TAGS_PATH + "?filter[rectype]=title").as(TagCollection.class); + + var expected = buildTagCollection(Collections.emptyList()); + assertEquals(expected, col); + } + + @Test + void shouldFailOnInvalidRecordTypeOnGet() { + var error = getWithStatus(TAGS_PATH + "?filter[rectype]=INVALID&filter[rectype]=title", SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid 'filter[rectype]' parameter value"); + } + + @Test + void shouldReturnAllUniqueTags() { + var tags = mapItems(saveTags(UNIQUE_TAGS, vertx), DbTag::getValue); + + var col = getWithOk(TAGS_PATH + "/summary").as(TagUniqueCollection.class); + + assertEquals(4, col.getData().size()); + assertEquals(Integer.valueOf(4), col.getMeta().getTotalResults()); + assertTrue(checkContainingOfUniqueTags(tags, col)); + } + + @Test + void shouldReturnEmptyUniqueTagsCollection() { + var col = getWithOk(TAGS_PATH + "/summary").as(TagUniqueCollection.class); + + assertEquals(0, col.getData().size()); + assertEquals(Integer.valueOf(0), col.getMeta().getTotalResults()); + } + + @Test + void shouldReturnListOfUniqueTagsWithParamsResources() { + var tags = mapItems(saveTags(UNIQUE_TAGS, vertx), DbTag::getValue); + + var col = getWithOk(TAGS_PATH + "/summary?filter[rectype]=resource").as( + TagUniqueCollection.class); + + assertEquals(1, col.getData().size()); + assertEquals(Integer.valueOf(1), col.getMeta().getTotalResults()); + assertTrue(checkContainingOfUniqueTags(tags, col)); + } + + @Test + void shouldReturnListOfUniqueTagsWithMultipleParams() { + var tags = mapItems(saveTags(UNIQUE_TAGS, vertx), DbTag::getValue); + + var col = getWithOk(TAGS_PATH + "/summary?filter[rectype]=resource&filter[rectype]=provider").as( + TagUniqueCollection.class); + + assertEquals(2, col.getData().size()); + assertEquals(Integer.valueOf(2), col.getMeta().getTotalResults()); + assertTrue(checkContainingOfUniqueTags(tags, col)); + } + + @Test + void shouldReturnBadRequestWithInvalidParams() { + var error = getWithStatus(TAGS_PATH + "/summary?filter[rectype]=INVALID&filter[rectype]=title", + SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid 'filter[rectype]' parameter value"); + } + + private boolean checkContainingOfUniqueTags(List<String> source, TagUniqueCollection collection) { + return source.containsAll(mapItems(collection.getData(), + tagUniqueCollectionItem -> tagUniqueCollectionItem.getAttributes().getValue())); + } + + private List<TagCollectionItem> toTagCollectionItems(List<DbTag> tags) { + return mapItems(tags, tagConverter::convert); + } + + private List<TagCollectionItem> sort(List<TagCollectionItem> items) { + var result = new ArrayList<TagCollectionItem>(items); + result.sort(Comparator.comparing(o -> o.getAttributes().getValue())); + return result; + } + + private TagCollection buildTagCollection(List<DbTag> tags) { + return new TagCollection() + .withData(sort(toTagCollectionItems(tags))) + .withMeta(new MetaTotalResults().withTotalResults(tags.size())) + .withJsonapi(RestConstants.JSONAPI); + } + + private List<DbTag> filter(List<DbTag> tags, Predicate<DbTag> filter) { + var found = tags.stream().filter(filter).toList(); + + if (CollectionUtils.isEmpty(found)) { + throw new IllegalArgumentException("Cannot find any tag matching the filter predicate"); + } else { + return found; + } + } + + private Predicate<DbTag> similarTo(DbTag expected) { + return tag -> expected.getValue().equals(tag.getValue()) + && expected.getRecordId().equals(tag.getRecordId()) + && expected.getRecordType().equals(tag.getRecordType()); + } +} diff --git a/src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java new file mode 100644 index 000000000..67303fe3a --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java @@ -0,0 +1,543 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; +import static org.folio.repository.RecordType.RESOURCE; +import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; +import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; +import static org.folio.repository.holdings.HoldingsTableConstants.HOLDINGS_TABLE; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.repository.resources.ResourceTableConstants.RESOURCES_TABLE_NAME; +import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; +import static org.folio.repository.titles.TitlesTableConstants.TITLES_TABLE_NAME; +import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME; +import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME_2; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; +import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; +import static org.folio.util.AccessTypesTestUtil.testData; +import static org.folio.util.AssertTestUtil.assertEqualsLong; +import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; +import static org.folio.util.AssertTestUtil.assertJsonEqual; +import static org.folio.util.KbCredentialsTestUtil.setupDefaultKbConfiguration; +import static org.folio.util.ResourcesTestUtil.buildResource; +import static org.folio.util.ResourcesTestUtil.saveResource; +import static org.folio.util.TagsTestUtil.saveTag; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import io.vertx.core.json.Json; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.folio.repository.RecordType; +import org.folio.rest.jaxrs.model.Errors; +import org.folio.rest.jaxrs.model.JsonapiError; +import org.folio.rest.jaxrs.model.Tags; +import org.folio.rest.jaxrs.model.Title; +import org.folio.rest.jaxrs.model.TitleCollection; +import org.folio.rest.jaxrs.model.TitlePostRequest; +import org.folio.rest.jaxrs.model.TitlePutRequest; +import org.folio.util.IntegrationTestBase; +import org.folio.util.TagsTestUtil; +import org.folio.util.TitlesTestUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class EholdingsTitlesIntegrationTest extends IntegrationTestBase { + + private static final String EHOLDINGS_TITLES_PATH = "eholdings/titles"; + + // RMAPI stub response files + private static final String RMAPI_TITLES_SEARCH_RESPONSE = + "responses/rmapi/titles/searchTitles.json"; + private static final String RMAPI_TITLE_BY_ID_RESPONSE = + "responses/rmapi/titles/get-title-by-id-response.json"; + private static final String RMAPI_TITLE_BY_ID_2_RESPONSE = + "responses/rmapi/titles/get-title-by-id-2-response.json"; + private static final String RMAPI_TITLE_NOT_FOUND_RESPONSE = + "responses/rmapi/titles/get-title-by-id-not-found-response.json"; + private static final String RMAPI_TITLE_WITH_RESOURCES_RESPONSE = + "responses/rmapi/titles/get-title-by-id-response-with-resources.json"; + private static final String RMAPI_POST_TITLE_RESPONSE = + "responses/rmapi/titles/post-title-response.json"; + private static final String RMAPI_TITLE_FOR_POST_RESPONSE = + "responses/rmapi/titles/get-title-by-id-for-post-request.json"; + private static final String RMAPI_PACKAGE_400_RESPONSE = + "responses/rmapi/packages/post-package-400-error-response.json"; + private static final String RMAPI_RESOURCE_UPDATED_RESPONSE = + "responses/rmapi/resources/get-custom-resource-updated-response.json"; + private static final String RMAPI_RESOURCE_UPDATED_TITLE_NAME_RESPONSE = + "responses/rmapi/resources/get-custom-resource-updated-title-name-response.json"; + private static final String RMAPI_MANAGED_RESOURCE_UPDATED_RESPONSE = + "responses/rmapi/resources/get-managed-resource-updated-response.json"; + + // KB-EBSCO expected response files + private static final String EXPECTED_TITLES_RESPONSE = + "responses/kb-ebsco/titles/expected-titles.json"; + private static final String EXPECTED_TITLES_WITH_RESOURCES_RESPONSE = + "responses/kb-ebsco/titles/expected-titles-with-resources.json"; + private static final String EXPECTED_TAGGED_TITLES_RESPONSE = + "responses/kb-ebsco/titles/expected-tagged-titles.json"; + private static final String EXPECTED_TAGGED_TITLES_WITH_RESOURCES_RESPONSE = + "responses/kb-ebsco/titles/expected-tagged-titles-with-resources.json"; + private static final String EXPECTED_TITLE_BY_ID_RESPONSE = + "responses/kb-ebsco/titles/expected-title-by-id.json"; + private static final String EXPECTED_TITLE_WITH_RESOURCES_RESPONSE = + "responses/kb-ebsco/titles/get-title-by-id-include-resources-response.json"; + private static final String EXPECTED_TITLE_WITH_RESOURCES_AND_TAGS_RESPONSE = + "responses/kb-ebsco/titles/get-title-by-id-include-resources-with-tags-response.json"; + private static final String EXPECTED_TITLE_INVALID_INCLUDE_RESPONSE = + "responses/kb-ebsco/titles/get-title-by-id-invalid-include-response.json"; + private static final String EXPECTED_CREATED_TITLE_RESPONSE = + "responses/kb-ebsco/titles/get-created-title-response.json"; + private static final String EXPECTED_UPDATED_TITLE_RESPONSE = + "responses/kb-ebsco/titles/expected-updated-title.json"; + + // Request files + private static final String POST_TITLE_REQUEST = + "requests/kb-ebsco/title/post-title-request.json"; + private static final String PUT_TITLE_REQUEST = + "requests/kb-ebsco/title/put-title.json"; + private static final String PUT_TITLE_NULL_NAME_REQUEST = + "requests/kb-ebsco/title/put-title-null-name.json"; + private static final String RMAPI_PUT_RESOURCE_REQUEST = + "requests/rmapi/resources/put-custom-resource-is-selected-multiple-attributes.json"; + + private String credentialsId; + + @BeforeEach + void setUp() { + credentialsId = setupDefaultKbConfiguration(getWiremockUrl(), vertx); + } + + @AfterEach + void tearDown() { + clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); + clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); + clearDataFromTable(vertx, HOLDINGS_TABLE); + clearDataFromTable(vertx, TAGS_TABLE_NAME); + clearDataFromTable(vertx, TITLES_TABLE_NAME); + clearDataFromTable(vertx, RESOURCES_TABLE_NAME); + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldReturnTitlesOnGet() { + mockSearchTitles(RMAPI_TITLES_SEARCH_RESPONSE); + + var actualResponse = getWithOk(EHOLDINGS_TITLES_PATH + "?page=1&filter[name]=Mind&sort=name").asString(); + assertJsonEqual(readFile(EXPECTED_TITLES_RESPONSE), actualResponse); + } + + @Test + void shouldReturnTitlesOnGetWithResources() { + mockSearchTitles(RMAPI_TITLES_SEARCH_RESPONSE); + + var resourcePath = withInclude(EHOLDINGS_TITLES_PATH + "?page=1&filter[name]=Mind&sort=name", "resources"); + var actualResponse = getWithOk(resourcePath).asString(); + + assertJsonEqual(readFile(EXPECTED_TITLES_WITH_RESOURCES_RESPONSE), actualResponse); + } + + @Test + void shouldReturnTitlesOnSearchByTags() { + mockGetTitleById(STUB_MANAGED_TITLE_ID, RMAPI_TITLE_BY_ID_RESPONSE); + mockGetTitleById(STUB_MANAGED_TITLE_ID_2, RMAPI_TITLE_BY_ID_2_RESPONSE); + + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, credentialsId, STUB_TITLE_NAME), vertx); + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_2, credentialsId, STUB_CUSTOM_TITLE_NAME), vertx); + saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); + saveTag(vertx, STUB_MANAGED_RESOURCE_ID_2, RecordType.RESOURCE, STUB_TAG_VALUE_2); + + var actualResponse = getWithOk(withTagFilters(EHOLDINGS_TITLES_PATH, STUB_TAG_VALUE, STUB_TAG_VALUE_2)).asString(); + assertJsonEqual(readFile(EXPECTED_TAGGED_TITLES_RESPONSE), actualResponse); + } + + @Test + void shouldReturnTitlesOnSearchByTagsWithResources() { + mockGetTitleById(STUB_MANAGED_TITLE_ID, RMAPI_TITLE_BY_ID_RESPONSE); + mockGetTitleById(STUB_MANAGED_TITLE_ID_2, RMAPI_TITLE_BY_ID_2_RESPONSE); + + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, credentialsId, STUB_TITLE_NAME), vertx); + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_2, credentialsId, STUB_CUSTOM_TITLE_NAME), vertx); + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_3, credentialsId, STUB_CUSTOM_TITLE_NAME), vertx); + saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); + saveTag(vertx, STUB_MANAGED_RESOURCE_ID_2, RecordType.RESOURCE, STUB_TAG_VALUE_2); + saveTag(vertx, STUB_MANAGED_RESOURCE_ID_3, RecordType.RESOURCE, STUB_TAG_VALUE_2); + + var resourcePath = + withInclude(withTagFilters(EHOLDINGS_TITLES_PATH, STUB_TAG_VALUE, STUB_TAG_VALUE_2), "resources"); + var actualResponse = getWithOk(resourcePath).asString(); + assertJsonEqual(readFile(EXPECTED_TAGGED_TITLES_WITH_RESOURCES_RESPONSE), actualResponse); + } + + @Test + void shouldReturnSecondTitleOnSearchByTagsWithPagination() { + mockGetTitleById(STUB_MANAGED_TITLE_ID, RMAPI_TITLE_BY_ID_RESPONSE); + mockGetTitleById(STUB_MANAGED_TITLE_ID_2, RMAPI_TITLE_BY_ID_2_RESPONSE); + + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, credentialsId, STUB_TITLE_NAME), vertx); + saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_2, credentialsId, STUB_CUSTOM_TITLE_NAME), vertx); + saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); + saveTag(vertx, STUB_MANAGED_RESOURCE_ID_2, RecordType.RESOURCE, STUB_TAG_VALUE_2); + + var resourcePath = withTagFilters(EHOLDINGS_TITLES_PATH + "?page=2&count=1", STUB_TAG_VALUE, STUB_TAG_VALUE_2); + var response = getWithOk(resourcePath).as(TitleCollection.class); + assertEquals(STUB_MANAGED_TITLE_ID_2, Integer.parseInt(response.getData().getFirst().getId())); + } + + @Test + void shouldReturnTitlesOnSearchByAccessTypes() { + var accessTypes = insertAccessTypes(testData(credentialsId), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.getFirst().getId(), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.getFirst().getId(), vertx); + mockGetTitles(); + + var resourcePath = withAccessTypeFilters(EHOLDINGS_TITLES_PATH, STUB_ACCESS_TYPE_NAME); + var titleCollection = getWithOk(resourcePath).as(TitleCollection.class); + var titles = titleCollection.getData(); + + assertEquals(2, titles.size()); + assertEquals(2, (int) titleCollection.getMeta().getTotalResults()); + assertThat(titles, everyItem(hasProperty("id", + anyOf(equalTo(String.valueOf(STUB_MANAGED_TITLE_ID)), equalTo(String.valueOf(STUB_MANAGED_TITLE_ID_2)))))); + } + + @Test + void shouldReturnTitlesWithResourcesOnSearchByAccessTypes() { + var accessTypes = insertAccessTypes(testData(credentialsId), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.getFirst().getId(), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.getFirst().getId(), vertx); + mockGetTitles(); + + var resourcePath = withInclude(withAccessTypeFilters(EHOLDINGS_TITLES_PATH, STUB_ACCESS_TYPE_NAME), "resources"); + var titleCollection = getWithOk(resourcePath).as(TitleCollection.class); + var titles = titleCollection.getData(); + + assertEquals(2, titles.size()); + assertEquals(2, (int) titleCollection.getMeta().getTotalResults()); + assertThat(titles, everyItem(hasProperty("id", + anyOf(equalTo(String.valueOf(STUB_MANAGED_TITLE_ID)), equalTo(String.valueOf(STUB_MANAGED_TITLE_ID_2)))))); + assertThat(titles, everyItem(hasProperty("included", not(empty())))); + } + + @Test + void shouldReturnTitleOnSearchByAccessTypesWithPagination() { + var accessTypes = insertAccessTypes(testData(credentialsId), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.get(0).getId(), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.get(1).getId(), vertx); + mockGetTitles(); + + var resourcePath = withAccessTypeFilters(EHOLDINGS_TITLES_PATH + "?page=2&count=1", + STUB_ACCESS_TYPE_NAME, STUB_ACCESS_TYPE_NAME_2); + var titleCollection = getWithOk(resourcePath).as(TitleCollection.class); + var titles = titleCollection.getData(); + + assertEquals(1, titles.size()); + assertEquals(2, (int) titleCollection.getMeta().getTotalResults()); + assertThat(titles, everyItem(hasProperty("id", equalTo(String.valueOf(STUB_MANAGED_TITLE_ID))))); + } + + @Test + void shouldReturnEmptyTitlesOnSearchByAccessTypesThatIsNotExist() { + var accessTypes = insertAccessTypes(testData(credentialsId), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.get(0).getId(), vertx); + insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.get(1).getId(), vertx); + mockGetTitles(); + + var resourcePath = withAccessTypeFilters(EHOLDINGS_TITLES_PATH, "Not Exist"); + var titleCollection = getWithOk(resourcePath).as(TitleCollection.class); + var titles = titleCollection.getData(); + + assertEquals(0, titles.size()); + assertEquals(0, (int) titleCollection.getMeta().getTotalResults()); + } + + @Test + void shouldReturnTitlesOnSearchByPackageIds() { + mockSearchTitles(RMAPI_TITLES_SEARCH_RESPONSE); + + var queryParam = "?filter[packageIds]=1&filter[packageIds]=2&filter[packageIds]=3&filter[name]=Mind"; + var actualResponse = getWithOk(EHOLDINGS_TITLES_PATH + queryParam).asString(); + assertJsonEqual(readFile(EXPECTED_TITLES_RESPONSE), actualResponse); + } + + @Test + void shouldReturn400ValidationErrorForPackageIds() { + var queryParam = "?filter[packageIds]=1&filter[packageIds]=abc&filter[name]=Mind"; + var error = getWithStatus(EHOLDINGS_TITLES_PATH + queryParam, SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid Query Parameter for filter[packageIds]"); + } + + @Test + void shouldReturn400IfCountOutOfRange() { + var error = getWithStatus(EHOLDINGS_TITLES_PATH + "?count=1000&page=1&filter[name]=Mind&sort=name", + SC_BAD_REQUEST).as(JsonapiError.class); + + assertErrorContainsTitle(error, "parameter value {1000} is not valid"); + } + + @Test + void shouldReturn500WhenRmApiReturns500Error() { + mockGet(matching(titlesRmApi() + ".*"), SC_INTERNAL_SERVER_ERROR); + + var resourcePath = EHOLDINGS_TITLES_PATH + "?filter[name]=news"; + var error = getWithStatus(resourcePath, SC_INTERNAL_SERVER_ERROR).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid RMAPI response"); + } + + @Test + void shouldReturnTitleWhenValidId() { + mockSearchTitles(RMAPI_TITLE_BY_ID_RESPONSE); + + var actualResponse = getWithOk(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID).asString(); + assertJsonEqual(readFile(EXPECTED_TITLE_BY_ID_RESPONSE), actualResponse); + } + + @Test + void shouldReturnTitleTagsWhenValidId() { + saveTag(vertx, STUB_MANAGED_TITLE_ID, RecordType.TITLE, STUB_TAG_VALUE); + mockSearchTitles(RMAPI_TITLE_BY_ID_RESPONSE); + + var actualResponse = getWithOk(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID).as(Title.class); + + assertTrue(actualResponse.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); + } + + @Test + void shouldReturn404WhenRmApiNotFoundOnTitleGet() { + mockGet(matching(titlesRmApi() + ".*"), + readFile(RMAPI_TITLE_NOT_FOUND_RESPONSE), SC_NOT_FOUND); + + var error = getWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, SC_NOT_FOUND) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Title not found"); + } + + @Test + void shouldReturn400WhenValidationErrorOnTitleGet() { + var error = getWithStatus(EHOLDINGS_TITLES_PATH + "/12345aaa", SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Title id is invalid - 12345aaa"); + } + + @Test + void shouldReturn500WhenRmApiReturns500ErrorOnTitleGet() { + mockGet(matching(titlesRmApi() + ".*"), SC_INTERNAL_SERVER_ERROR); + + var error = getWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, + SC_INTERNAL_SERVER_ERROR).as(JsonapiError.class); + + assertErrorContainsTitle(error, "Invalid RMAPI response"); + } + + @Test + void shouldReturnTitleWithSortedResourcesWhenIncludeResources() { + mockSearchTitles(RMAPI_TITLE_WITH_RESOURCES_RESPONSE); + + var actual = getWithStatus(withInclude(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, "resources"), SC_OK).asString(); + + assertJsonEqual(readFile(EXPECTED_TITLE_WITH_RESOURCES_RESPONSE), actual); + } + + @Test + void shouldReturnTitleWithResourcesWhenIncludeResourcesWithTags() { + saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); + mockSearchTitles(RMAPI_TITLE_BY_ID_RESPONSE); + + var actual = getWithStatus(withInclude(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, "resources"), SC_OK).asString(); + + assertJsonEqual(readFile(EXPECTED_TITLE_WITH_RESOURCES_AND_TAGS_RESPONSE), actual); + } + + @Test + void shouldReturnTitleWithoutResourcesWhenInvalidInclude() { + mockSearchTitles(RMAPI_TITLE_BY_ID_RESPONSE); + + var actual = getWithStatus(withInclude(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, "badValue"), SC_OK).asString(); + + assertJsonEqual(readFile(EXPECTED_TITLE_INVALID_INCLUDE_RESPONSE), actual); + } + + @Test + void shouldReturnTitleWhenValidPostRequest() { + var actual = postTitle(Collections.emptyList()).asString(); + assertJsonEqual(readFile(EXPECTED_CREATED_TITLE_RESPONSE), actual); + } + + @Test + void shouldUpdateTagsWhenValidPostRequest() { + var tagList = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); + var actual = postTitle(tagList).as(Title.class); + var tagsFromDb = TagsTestUtil.getTags(vertx); + + assertThat(actual.getData().getAttributes().getTags().getTagList(), containsInAnyOrder(tagList.toArray())); + assertThat(tagsFromDb, containsInAnyOrder(tagList.toArray())); + } + + @Test + void shouldAddTitleDataOnPost() { + postTitle(Collections.singletonList(STUB_TAG_VALUE)); + + var titles = TitlesTestUtil.getTitles(vertx); + assertEquals(1, titles.size()); + assertEquals(STUB_TITLE_ID, titles.getFirst().getId()); + assertEquals("Test Title", titles.getFirst().getName()); + } + + @Test + void shouldReturn400WhenInvalidPostRequest() { + mockPost( + WireMock.equalTo(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID)), + readFile(RMAPI_PACKAGE_400_RESPONSE), + SC_BAD_REQUEST); + + var error = postWithStatus(EHOLDINGS_TITLES_PATH, + readFile(POST_TITLE_REQUEST), SC_BAD_REQUEST) + .as(JsonapiError.class); + + assertErrorContainsTitle(error, "Package with the provided name already exists"); + } + + @Test + void shouldReturnUpdatedValuesForCustomTitleOnSuccessfulPut() { + var actualResponse = putTitle(null); + assertJsonEqual(readFile(EXPECTED_UPDATED_TITLE_RESPONSE), actualResponse); + + verifyPut(WireMock.equalTo(resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID)), + equalToJson(readFile(RMAPI_PUT_RESOURCE_REQUEST))); + } + + @Test + void shouldUpdateTitleTagsOnSuccessfulPut() { + var newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); + putTitle(newTags); + + assertThat(TagsTestUtil.getTags(vertx), containsInAnyOrder(newTags.toArray())); + } + + @Test + void shouldUpdateOnlyTagsOnPutForNonCustomTitle() { + var request = readJsonFile(PUT_TITLE_REQUEST, TitlePutRequest.class); + var newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); + request.getData().getAttributes().setTags(new Tags().withTagList(newTags)); + mockGet(WireMock.equalTo(titlesRmApi(CUSTOM_TITLE_ID)), + readFile(RMAPI_MANAGED_RESOURCE_UPDATED_RESPONSE)); + + putWithOk(EHOLDINGS_TITLES_PATH + "/" + CUSTOM_TITLE_ID, Json.encode(request)); + + assertThat(TagsTestUtil.getTags(vertx), containsInAnyOrder(newTags.toArray())); + verifyPut(anyUrl(), 0); + } + + @Test + void shouldAddTitleDataOnPut() { + putTitle(Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); + + var titles = TitlesTestUtil.getTitles(vertx); + assertEquals(1, titles.size()); + assertEqualsLong(titles.getFirst().getId()); + assertEquals("sd-test-java-again", titles.getFirst().getName()); + } + + @Test + void shouldDeleteTitleDataOnPutWithEmptyTagList() { + putTitle(Collections.singletonList(STUB_TAG_VALUE)); + putTitle(Collections.emptyList()); + + assertTrue(TitlesTestUtil.getTitles(vertx).isEmpty()); + } + + @Test + void shouldUpdateTitleDataOnSecondPut() { + var newName = "new name"; + + putTitle(readFile(RMAPI_RESOURCE_UPDATED_TITLE_NAME_RESPONSE), Collections.singletonList(STUB_TAG_VALUE)); + + var request = readJsonFile(PUT_TITLE_REQUEST, TitlePutRequest.class); + request.getData().getAttributes().withName(newName); + mockGet(WireMock.equalTo(titlesRmApi(CUSTOM_TITLE_ID)), readFile(RMAPI_RESOURCE_UPDATED_TITLE_NAME_RESPONSE)); + + putWithOk(EHOLDINGS_TITLES_PATH + "/" + CUSTOM_TITLE_ID, Json.encode(request)); + + var titles = TitlesTestUtil.getTitles(vertx); + assertEquals(1, titles.size()); + assertEqualsLong(titles.getFirst().getId()); + assertEquals(newName, titles.getFirst().getName()); + } + + @Test + void shouldReturn422WhenNameIsNotProvided() { + var error = putWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, + readFile(PUT_TITLE_NULL_NAME_REQUEST), SC_UNPROCESSABLE_CONTENT) + .as(Errors.class); + + assertTrue(error.getErrors().getFirst().getMessage().contains("must not be null")); + } + + private String putTitle(List<String> tags) { + return putTitle(readFile(RMAPI_RESOURCE_UPDATED_RESPONSE), tags); + } + + private String putTitle(String updatedResourceResponse, List<String> tags) { + mockGet(WireMock.equalTo(titlesRmApi(CUSTOM_TITLE_ID)), updatedResourceResponse); + mockPut(matching(resourcesRmApi(CUSTOM_VENDOR_ID, CUSTOM_PACKAGE_ID, CUSTOM_TITLE_ID)), SC_NO_CONTENT); + + var titleToBeUpdated = readJsonFile(PUT_TITLE_REQUEST, TitlePutRequest.class); + if (tags != null) { + titleToBeUpdated.getData().getAttributes().setTags(new Tags().withTagList(tags)); + } + + return putWithOk(EHOLDINGS_TITLES_PATH + "/" + CUSTOM_TITLE_ID, Json.encode(titleToBeUpdated)).asString(); + } + + private ExtractableResponse<Response> postTitle(List<String> tags) { + mockPost(WireMock.equalTo(packageTitlesRmApi(STUB_VENDOR_ID, STUB_PACKAGE_ID)), + readFile(RMAPI_POST_TITLE_RESPONSE), SC_OK); + mockGet(matching(titlesRmApi(STUB_TITLE_ID)), readFile(RMAPI_TITLE_FOR_POST_RESPONSE)); + + var request = readJsonFile(POST_TITLE_REQUEST, TitlePostRequest.class); + request.getData().getAttributes().setTags(new Tags().withTagList(tags)); + + return postWithOk(EHOLDINGS_TITLES_PATH, Json.encode(request)); + } + + private void mockGetTitles() { + mockGetTitleById(STUB_MANAGED_TITLE_ID, RMAPI_TITLE_BY_ID_RESPONSE); + mockGetTitleById(STUB_MANAGED_TITLE_ID_2, RMAPI_TITLE_BY_ID_2_RESPONSE); + } + + private void mockGetTitleById(int titleId, String responseFile) { + mockGet(WireMock.equalTo(titlesRmApi(titleId)), readFile(responseFile)); + } + + private void mockSearchTitles(String responseFile) { + mockGet(matching(titlesRmApi() + ".*"), readFile(responseFile)); + } +} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsUsageConsolidationImplTest.java b/src/test/java/org/folio/rest/impl/EholdingsUsageConsolidationImplIntegrationTest.java similarity index 62% rename from src/test/java/org/folio/rest/impl/integrationsuite/EholdingsUsageConsolidationImplTest.java rename to src/test/java/org/folio/rest/impl/EholdingsUsageConsolidationImplIntegrationTest.java index 5b0dffd73..f3dff906f 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsUsageConsolidationImplTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsUsageConsolidationImplIntegrationTest.java @@ -1,25 +1,20 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; import static org.folio.repository.uc.UcCredentialsTableConstants.UC_CREDENTIALS_TABLE_NAME; import static org.folio.repository.uc.UcSettingsTableConstants.UC_SETTINGS_TABLE_NAME; import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; +import static org.folio.util.KbCredentialsTestUtil.API_URL; +import static org.folio.util.KbCredentialsTestUtil.CREDENTIALS_NAME; import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.clearDataFromTable; import static org.folio.util.UcCredentialsTestUtil.setUpUcCredentials; import static org.folio.util.UcSettingsTestUtil.METRIC_TYPE_PARAM_TRUE; import static org.folio.util.UcSettingsTestUtil.UC_SETTINGS_ENDPOINT; @@ -28,15 +23,10 @@ import static org.folio.util.UcSettingsTestUtil.getUcSettings; import static org.folio.util.UcSettingsTestUtil.saveUcSettings; import static org.folio.util.UcSettingsTestUtil.stubSettings; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; import java.util.UUID; -import org.folio.client.uc.UcApigeeEbscoClient; -import org.folio.client.uc.UcAuthEbscoClient; -import org.folio.client.uc.model.UcAuthToken; -import org.folio.rest.impl.WireMockTestBase; import org.folio.rest.jaxrs.model.JsonapiError; import org.folio.rest.jaxrs.model.Month; import org.folio.rest.jaxrs.model.PlatformType; @@ -48,46 +38,33 @@ import org.folio.rest.jaxrs.model.UCSettingsPatchRequestDataAttributes; import org.folio.rest.jaxrs.model.UCSettingsPostDataAttributes; import org.folio.rest.jaxrs.model.UCSettingsPostRequest; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.util.ReflectionTestUtils; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class EholdingsUsageConsolidationImplTest extends WireMockTestBase { +class EholdingsUsageConsolidationImplIntegrationTest extends IntegrationTestBase { private String credentialsId; - @Autowired - private UcAuthEbscoClient authEbscoClient; - @Autowired - private UcApigeeEbscoClient apigeeEbscoClient; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - ReflectionTestUtils.setField(authEbscoClient, "baseUrl", getWiremockUrl()); - ReflectionTestUtils.setField(apigeeEbscoClient, "baseUrl", getWiremockUrl()); - credentialsId = saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + @BeforeEach + void setUp() { + credentialsId = saveKbCredentials(API_URL, CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); } - @After - public void tearDown() { + @AfterEach + void tearDown() { clearDataFromTable(vertx, UC_CREDENTIALS_TABLE_NAME); clearDataFromTable(vertx, UC_SETTINGS_TABLE_NAME); clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); } @Test - public void shouldReturnUcSettingsOnGetByUserHeaders() { + void shouldReturnUcSettingsOnGetByUserHeaders() { UCSettings stubSettings = stubSettings(credentialsId); String settingsId = saveUcSettings(stubSettings, vertx); - UCSettings actual = getWithOk(UC_SETTINGS_USER_ENDPOINT, JOHN_USER_ID_HEADER).as(UCSettings.class); + UCSettings actual = getWithOk(UC_SETTINGS_USER_ENDPOINT).as(UCSettings.class); UCSettings expected = stubSettings.withId(settingsId); expected.getAttributes().withCustomerKey("*".repeat(40)); @@ -95,26 +72,26 @@ public void shouldReturnUcSettingsOnGetByUserHeaders() { } @Test - public void shouldReturnUcSettingsKeyOnGet() { + void shouldReturnUcSettingsKeyOnGet() { UCSettings stubSettings = stubSettings(credentialsId); String settingsId = saveUcSettings(stubSettings, vertx); String resourcePath = String.format(UC_SETTINGS_KEY_ENDPOINT, credentialsId); - UCSettingsKey actual = getWithOk(resourcePath, JOHN_USER_ID_HEADER).as(UCSettingsKey.class); + UCSettingsKey actual = getWithOk(resourcePath).as(UCSettingsKey.class); assertEquals(settingsId, actual.getId()); assertEquals(stubSettings.getAttributes().getCustomerKey(), actual.getAttributes().getCustomerKey()); } @Test - public void shouldReturnUcSettingsOnGetByUserHeadersWithMetricType() { + void shouldReturnUcSettingsOnGetByUserHeadersWithMetricType() { final UCSettings stubSettings = stubSettings(credentialsId); final String settingsId = saveUcSettings(stubSettings, vertx); setUpUcCredentials(vertx); mockMetricTypeWithExpectedTypeId(); mockAuthToken(); - UCSettings actual = getWithOk(UC_SETTINGS_USER_ENDPOINT + METRIC_TYPE_PARAM_TRUE, JOHN_USER_ID_HEADER) + var actual = getWithOk(UC_SETTINGS_USER_ENDPOINT + METRIC_TYPE_PARAM_TRUE) .as(UCSettings.class); UCSettings expected = stubSettings.withId(settingsId); @@ -124,7 +101,7 @@ public void shouldReturnUcSettingsOnGetByUserHeadersWithMetricType() { } @Test - public void shouldReturnUcSettingsOnGet() { + void shouldReturnUcSettingsOnGet() { UCSettings stubSettings = stubSettings(credentialsId); String settingsId = saveUcSettings(stubSettings, vertx); @@ -137,17 +114,17 @@ public void shouldReturnUcSettingsOnGet() { } @Test - public void shouldReturn404OnGetNotExistedSettings() { + void shouldReturn404OnGetNotExistedSettings() { String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); JsonapiError actual = getWithStatus(resourcePath, SC_NOT_FOUND).as(JsonapiError.class); String expectedErrorMessage = String.format("Usage Consolidation is not " - + "enabled for KB credentials with id [%s]", credentialsId); + + "enabled for KB credentials with id [%s]", credentialsId); assertErrorContainsTitle(actual, expectedErrorMessage); } @Test - public void shouldUpdateUcSettingsOnPatch() { + void shouldUpdateUcSettingsOnPatch() { setUpUcCredentials(vertx); mockAuthToken(); mockSuccessfulVerification(); @@ -162,14 +139,14 @@ public void shouldUpdateUcSettingsOnPatch() { .withCurrency(newCurrencyValue))); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - patchWithNoContent(resourcePath, Json.encode(patchData), JOHN_USER_ID_HEADER); + patchWithNoContent(resourcePath, Json.encode(patchData)); UCSettings actual = getUcSettings(vertx).getFirst(); assertEquals(newCurrencyValue, actual.getAttributes().getCurrency()); } @Test - public void shouldReturn422OnPatchWithInvalidCurrency() { + void shouldReturn422OnPatchWithInvalidCurrency() { mockAuthToken(); mockSuccessfulVerification(); setUpUcCredentials(vertx); @@ -184,16 +161,15 @@ public void shouldReturn422OnPatchWithInvalidCurrency() { .withCurrency(newCurrencyValue))); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - JsonapiError error = - patchWithStatus(resourcePath, Json.encode(patchData), SC_UNPROCESSABLE_ENTITY, JOHN_USER_ID_HEADER) - .as(JsonapiError.class); + var error = patchWithStatus(resourcePath, Json.encode(patchData), SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid value"); assertErrorContainsDetail(error, "Value 'VVV' is invalid for 'currency'"); } @Test - public void shouldReturn422OnPatchWithInvalidMonth() { + void shouldReturn422OnPatchWithInvalidMonth() { mockAuthToken(); mockSuccessfulVerification(); @@ -205,14 +181,13 @@ public void shouldReturn422OnPatchWithInvalidMonth() { String patchBody = Json.encode(patchData); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - JsonapiError error = - patchWithStatus(resourcePath, patchBody, SC_NOT_FOUND, JOHN_USER_ID_HEADER).as(JsonapiError.class); + var error = patchWithStatus(resourcePath, patchBody, SC_NOT_FOUND).as(JsonapiError.class); assertErrorContainsTitle(error, "Usage Consolidation is not enabled for KB credentials"); } @Test - public void shouldReturn422OnPatchWithInvalidCustomerKey() { + void shouldReturn422OnPatchWithInvalidCustomerKey() { mockAuthToken(); mockFailed400Verification(); setUpUcCredentials(vertx); @@ -225,21 +200,21 @@ public void shouldReturn422OnPatchWithInvalidCustomerKey() { String patchBody = Json.encode(patchData); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY, JOHN_USER_ID_HEADER) + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid UC Credentials"); } @Test - public void shouldReturn201OnPostSettingsWithDefaultValues() { + void shouldReturn201OnPostSettingsWithDefaultValues() { mockAuthToken(); mockSuccessfulVerification(); setUpUcCredentials(vertx); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); String postBody = Json.encode(getPostRequest()); - UCSettings ucSettings = postWithCreated(resourcePath, postBody, JOHN_USER_ID_HEADER).as(UCSettings.class); + UCSettings ucSettings = postWithCreated(resourcePath, postBody).as(UCSettings.class); assertEquals(credentialsId, ucSettings.getAttributes().getCredentialsId()); assertEquals(Month.JAN, ucSettings.getAttributes().getStartMonth()); @@ -247,14 +222,14 @@ public void shouldReturn201OnPostSettingsWithDefaultValues() { } @Test - public void shouldReturn201OnPostSettingsWhenDataIsValid() { + void shouldReturn201OnPostSettingsWhenDataIsValid() { mockAuthToken(); mockSuccessfulVerification(); setUpUcCredentials(vertx); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); String postBody = Json.encode(getPostRequestNoDefault()); - UCSettings ucSettings = postWithCreated(resourcePath, postBody, JOHN_USER_ID_HEADER).as(UCSettings.class); + UCSettings ucSettings = postWithCreated(resourcePath, postBody).as(UCSettings.class); assertEquals(credentialsId, ucSettings.getAttributes().getCredentialsId()); assertEquals(Month.FEB, ucSettings.getAttributes().getStartMonth()); @@ -263,7 +238,7 @@ public void shouldReturn201OnPostSettingsWhenDataIsValid() { } @Test - public void shouldReturn422OnPostSettingsWhenCurrencyIsInvalid() { + void shouldReturn422OnPostSettingsWhenCurrencyIsInvalid() { mockAuthToken(); mockSuccessfulVerification(); setUpUcCredentials(vertx); @@ -272,15 +247,15 @@ public void shouldReturn422OnPostSettingsWhenCurrencyIsInvalid() { var postRequest = getPostRequestNoDefault(); postRequest.getData().getAttributes().setCurrency("aaa"); String postBody = Json.encode(postRequest); - JsonapiError error = - postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY, JOHN_USER_ID_HEADER).as(JsonapiError.class); + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid value"); assertErrorContainsDetail(error, "is invalid for 'currency'"); } @Test - public void shouldReturn422WhenKbCredentialsNotExist() { + void shouldReturn422WhenKbCredentialsNotExist() { mockAuthToken(); mockSuccessfulVerification(); setUpUcCredentials(vertx); @@ -288,8 +263,8 @@ public void shouldReturn422WhenKbCredentialsNotExist() { String randomCredentialsId = UUID.randomUUID().toString(); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, randomCredentialsId); String postBody = Json.encode(getPostRequest()); - JsonapiError error = - postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY, JOHN_USER_ID_HEADER).as(JsonapiError.class); + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); String expectedErrorMessage = String.format("'%s' is invalid for 'kb_credentials_id'", randomCredentialsId); assertErrorContainsTitle(error, "Invalid value"); @@ -297,17 +272,17 @@ public void shouldReturn422WhenKbCredentialsNotExist() { } @Test - public void shouldReturn422WhenSaveTwoEntitiesWithSameCredentialsId() { + void shouldReturn422WhenSaveTwoEntitiesWithSameCredentialsId() { mockAuthToken(); mockSuccessfulVerification(); setUpUcCredentials(vertx); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); String postBody = Json.encode(getPostRequest()); - postWithCreated(resourcePath, postBody, JOHN_USER_ID_HEADER); + postWithCreated(resourcePath, postBody); - JsonapiError error = - postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY, JOHN_USER_ID_HEADER).as(JsonapiError.class); + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); String expectedErrorMessage = String.format("'%s' is invalid for", credentialsId); assertErrorContainsTitle(error, "Invalid value"); @@ -315,67 +290,33 @@ public void shouldReturn422WhenSaveTwoEntitiesWithSameCredentialsId() { } @Test - public void shouldReturn422WhenUcCredentialNotExist() { + void shouldReturn422WhenUcCredentialNotExist() { clearDataFromTable(vertx, UC_CREDENTIALS_TABLE_NAME); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); String postBody = Json.encode(getPostRequest()); - JsonapiError error = - postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY, JOHN_USER_ID_HEADER).as(JsonapiError.class); + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) + .as(JsonapiError.class); String expectedErrorMessage = "Invalid UC API Credentials"; assertErrorContainsTitle(error, expectedErrorMessage); } - @Test - public void shouldReturn401WhenNoHeaderProvided() { - mockAuthToken(); - mockSuccessfulVerification(); - setUpUcCredentials(vertx); - - String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - String postBody = Json.encode(getPostRequest()); - JsonapiError error = postWithStatus(resourcePath, postBody, SC_UNAUTHORIZED).as(JsonapiError.class); - - assertErrorContainsTitle(error, "X-Okapi-User-Id header is required"); - } - - @Test - public void shouldReturn401WhenAuthTokenExpired() { - mockAuthToken(); - mockFailed401Verification(); - setUpUcCredentials(vertx); - - String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - String postBody = Json.encode(getPostRequest()); - JsonapiError error = postWithStatus(resourcePath, postBody, SC_UNAUTHORIZED).as(JsonapiError.class); - - assertErrorContainsTitle(error, "X-Okapi-User-Id header is required"); - } - private void mockSuccessfulVerification() { - stubFor(get(urlMatching("/uc/costperuse.*")).willReturn(aResponse().withStatus(SC_OK))); + mockGet(matching("/uc/costperuse.*"), SC_OK); } private void mockFailed400Verification() { - stubFor(get(urlMatching("/uc/costperuse.*")).willReturn(aResponse().withStatus(SC_BAD_REQUEST))); - } - - private void mockFailed401Verification() { - stubFor(get(urlMatching("/uc/costperuse.*")).willReturn(aResponse().withStatus(SC_UNAUTHORIZED))); - } - - private void mockAuthToken() { - UcAuthToken stubToken = new UcAuthToken("access_token", "Bearer", 3600L, "openid"); - stubFor(post(urlPathMatching("/oauth-proxy/token")) - .willReturn(aResponse().withStatus(SC_OK).withBody(Json.encode(stubToken))) - ); + mockGet(matching("/uc/costperuse.*"), SC_BAD_REQUEST); } private void mockMetricTypeWithExpectedTypeId() { - stubFor(get(urlMatching("/uc/usageanalysis/analysismetrictype")) - .willReturn(aResponse().withStatus(SC_OK) - .withBody("{\"metricTypeId\":33,\"description\":\"R5 - Total_Item_Requests\"}"))); + mockGet(equalTo("/uc/usageanalysis/analysismetrictype"), """ + { + "metricTypeId": 33, + "description": "R5 - Total_Item_Requests" + } + """); } private UCSettingsPostRequest getPostRequest() { diff --git a/src/test/java/org/folio/rest/impl/IntegrationTestSuite.java b/src/test/java/org/folio/rest/impl/IntegrationTestSuite.java deleted file mode 100644 index 5c909b48b..000000000 --- a/src/test/java/org/folio/rest/impl/IntegrationTestSuite.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.folio.rest.impl; - -import java.util.Collections; -import org.folio.rest.impl.integrationsuite.DefaultLoadHoldingsImplTest; -import org.folio.rest.impl.integrationsuite.DefaultLoadServiceFacadeTest; -import org.folio.rest.impl.integrationsuite.EholdingsAccessTypesImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsAssignedUsersImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsCostperuseImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsCurrenciesImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsCustomLabelsImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsKbCredentialsImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsPackagesTest; -import org.folio.rest.impl.integrationsuite.EholdingsProvidersImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsProxyTypesImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsResourcesImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsRootProxyImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsStatusTest; -import org.folio.rest.impl.integrationsuite.EholdingsTagsImplTest; -import org.folio.rest.impl.integrationsuite.EholdingsTitlesTest; -import org.folio.rest.impl.integrationsuite.EholdingsUsageConsolidationImplTest; -import org.folio.rest.impl.integrationsuite.LoadHoldingsStatusImplTest; -import org.folio.rest.impl.integrationsuite.TransactionLoadServiceFacadeTest; -import org.folio.rest.impl.integrationsuite.UsageConsolidationCredentialsApiTest; -import org.folio.test.util.TestSetUpHelper; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@Suite.SuiteClasses({ - EholdingsPackagesTest.class, - EholdingsProvidersImplTest.class, - EholdingsProxyTypesImplTest.class, - EholdingsResourcesImplTest.class, - EholdingsRootProxyImplTest.class, - EholdingsCustomLabelsImplTest.class, - EholdingsStatusTest.class, - EholdingsTitlesTest.class, - EholdingsTagsImplTest.class, - DefaultLoadHoldingsImplTest.class, - LoadHoldingsStatusImplTest.class, - DefaultLoadServiceFacadeTest.class, - TransactionLoadServiceFacadeTest.class, - EholdingsAccessTypesImplTest.class, - EholdingsKbCredentialsImplTest.class, - EholdingsAssignedUsersImplTest.class, - EholdingsCurrenciesImplTest.class, - EholdingsUsageConsolidationImplTest.class, - EholdingsCostperuseImplTest.class, - UsageConsolidationCredentialsApiTest.class -}) -@RunWith(Suite.class) -public class IntegrationTestSuite { - - @BeforeClass - public static void setUpClass() { - TestSetUpHelper.startVertxAndPostgres( - Collections.singletonMap("spring.configuration", "org.folio.spring.config.TestConfig")); - } - - @AfterClass - public static void tearDownClass() { - TestSetUpHelper.stopVertxAndPostgres(); - } -} diff --git a/src/test/java/org/folio/rest/impl/PackagesTestData.java b/src/test/java/org/folio/rest/impl/PackagesTestData.java deleted file mode 100644 index b1c2d22a9..000000000 --- a/src/test/java/org/folio/rest/impl/PackagesTestData.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.folio.rest.impl; - -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID_2; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID_3; - -import org.folio.rest.jaxrs.model.PackagePutData; -import org.folio.rest.jaxrs.model.PackagePutDataAttributes; -import org.folio.rest.jaxrs.model.PackagePutRequest; - -public class PackagesTestData { - - public static final String STUB_PACKAGE_ID = "3964"; - public static final String STUB_PACKAGE_ID_2 = "13964"; - public static final String STUB_PACKAGE_ID_3 = "23964"; - - public static final String STUB_PACKAGE_NAME = "EBSCO Biotechnology Collection: India"; - public static final String STUB_PACKAGE_NAME_2 = "package 2"; - public static final String STUB_PACKAGE_NAME_3 = "package 3"; - - public static final String STUB_PACKAGE_CONTENT_TYPE = "AggregatedFullText"; - - public static final String FULL_PACKAGE_ID = STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID; - public static final String FULL_PACKAGE_ID_2 = STUB_VENDOR_ID_2 + "-" + STUB_PACKAGE_ID_2; - public static final String FULL_PACKAGE_ID_3 = STUB_VENDOR_ID_3 + "-" + STUB_PACKAGE_ID_3; - public static final String FULL_PACKAGE_ID_4 = STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID_2; - public static final String FULL_PACKAGE_ID_5 = STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID_3; - - public static PackagePutRequest getPackagePutRequest(PackagePutDataAttributes attributes) { - return new PackagePutRequest() - .withData(new PackagePutData() - .withType(PackagePutData.Type.PACKAGES) - .withAttributes(attributes)); - } -} diff --git a/src/test/java/org/folio/rest/impl/ProvidersTestData.java b/src/test/java/org/folio/rest/impl/ProvidersTestData.java deleted file mode 100644 index 13be31a11..000000000 --- a/src/test/java/org/folio/rest/impl/ProvidersTestData.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.folio.rest.impl; - -public class ProvidersTestData { - public static final String STUB_VENDOR_ID = "19"; - public static final String STUB_VENDOR_ID_2 = "153"; - public static final String STUB_VENDOR_ID_3 = "167"; - - public static final String STUB_VENDOR_NAME = "Vendor Name1"; - public static final String STUB_VENDOR_NAME_2 = "Vendor Name2"; - public static final String STUB_VENDOR_NAME_3 = "Vendor Name3"; - public static final String PROVIDER_TAGS_PATH = "eholdings/providers/" + STUB_VENDOR_ID + "/tags"; -} diff --git a/src/test/java/org/folio/rest/impl/ResourcesTestData.java b/src/test/java/org/folio/rest/impl/ResourcesTestData.java deleted file mode 100644 index 9efaf26ef..000000000 --- a/src/test/java/org/folio/rest/impl/ResourcesTestData.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.folio.rest.impl; - -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID_2; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_PACKAGE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_VENDOR_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_MANAGED_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_MANAGED_TITLE_ID_2; - -import java.util.Collections; -import org.folio.holdingsiq.model.CoverageDates; -import org.folio.holdingsiq.model.CustomerResources; -import org.folio.holdingsiq.model.EmbargoPeriod; -import org.folio.holdingsiq.model.ProxyUrl; -import org.folio.holdingsiq.model.Title; -import org.folio.holdingsiq.model.UserDefinedFields; -import org.folio.holdingsiq.model.VisibilityInfo; -import org.folio.rest.jaxrs.model.ResourcePutData; -import org.folio.rest.jaxrs.model.ResourcePutDataAttributes; -import org.folio.rest.jaxrs.model.ResourcePutRequest; -import org.folio.rmapi.result.ResourceResult; - -public class ResourcesTestData { - public static final String OLD_PROXY_ID = "<n>"; - public static final String OLD_COVERAGE_STATEMENT = "statement"; - public static final String OLD_URL = "http://example.com"; - public static final boolean OLD_VISIBILITY_DATA = true; - public static final String OLD_BEGIN_COVERAGE = "2002-10-10"; - public static final String OLD_END_COVERAGE = "2003-10-10"; - public static final String OLD_EMBARGO_UNIT = "Day"; - public static final int OLD_EMBARGO_VALUE = 5; - - public static final String STUB_MANAGED_RESOURCE_ID = - STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID + "-" + STUB_MANAGED_TITLE_ID; - public static final String STUB_MANAGED_RESOURCE_ID_2 = - STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID + "-" + STUB_MANAGED_TITLE_ID_2; - public static final String STUB_MANAGED_RESOURCE_ID_3 = - STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID_2 + "-" + STUB_MANAGED_TITLE_ID_2; - public static final String STUB_CUSTOM_RESOURCE_ID = - STUB_CUSTOM_VENDOR_ID + "-" + STUB_CUSTOM_PACKAGE_ID + "-" + STUB_CUSTOM_TITLE_ID; - - public static ResourcePutRequest getResourcePutRequest(ResourcePutDataAttributes attributes) { - return new ResourcePutRequest() - .withData(new ResourcePutData() - .withType(ResourcePutData.Type.RESOURCES) - .withAttributes(attributes)); - } - - public static ResourceResult createResourceData() { - Title title = Title.builder() - .contributorsList(Collections.emptyList()) - .customerResourcesList(Collections.singletonList(CustomerResources.builder() - .coverageStatement(OLD_COVERAGE_STATEMENT) - .isSelected(false) - .visibilityData(VisibilityInfo.builder() - .isHidden(OLD_VISIBILITY_DATA).build()) - .customCoverageList(Collections.singletonList(CoverageDates.builder() - .beginCoverage(OLD_BEGIN_COVERAGE).endCoverage(OLD_END_COVERAGE).build())) - .customEmbargoPeriod(EmbargoPeriod.builder() - .embargoUnit(OLD_EMBARGO_UNIT).embargoValue(OLD_EMBARGO_VALUE).build()) - .proxy(ProxyUrl.builder().proxiedUrl(OLD_URL) - .id(OLD_PROXY_ID).inherited(true).build()) - .url(OLD_URL) - .userDefinedFields(UserDefinedFields.builder().build()) - .build() - )) - .identifiersList(Collections.emptyList()) - .subjectsList(Collections.emptyList()) - .titleId(1) - .build(); - return new ResourceResult( - title, null, null, false); - } -} diff --git a/src/test/java/org/folio/rest/impl/RmApiConstants.java b/src/test/java/org/folio/rest/impl/RmApiConstants.java deleted file mode 100644 index a735599ac..000000000 --- a/src/test/java/org/folio/rest/impl/RmApiConstants.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.folio.rest.impl; - -import static org.folio.rest.impl.WireMockTestBase.STUB_CUSTOMER_ID; - -public class RmApiConstants { - - public static final String RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/"; - public static final String RMAPI_PROXIES_URL = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/proxies.*"; - - public static final String RMAPI_HOLDINGS_STATUS_URL = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/holdings/status"; - public static final String RMAPI_POST_HOLDINGS_URL = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/holdings"; - - public static final String RMAPI_TRANSACTION_STATUS_URL = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/reports/holdings/transactions/%s/status"; - public static final String RMAPI_POST_TRANSACTIONS_HOLDINGS_URL = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/reports/holdings"; - public static final String RMAPI_TRANSACTIONS_URL = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/reports/holdings/transactions"; - public static final String RMAPI_TRANSACTION_BY_ID_URL = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/reports/holdings/transactions/%s"; - public static final String RMAPI_DELTAS_URL = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/reports/holdings/deltas"; - public static final String RMAPI_DELTA_BY_ID_URL = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/reports/holdings/deltas/%s"; - public static final String RMAPI_DELTA_STATUS_URL = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/reports/holdings/deltas/%s/status"; -} diff --git a/src/test/java/org/folio/rest/impl/TagsTestData.java b/src/test/java/org/folio/rest/impl/TagsTestData.java deleted file mode 100644 index e4fcf18c2..000000000 --- a/src/test/java/org/folio/rest/impl/TagsTestData.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.folio.rest.impl; - -public class TagsTestData { - public static final String STUB_TAG_VALUE = "tag one"; - public static final String STUB_TAG_VALUE_2 = "tag 2"; - public static final String STUB_TAG_VALUE_3 = "tag 3"; -} diff --git a/src/test/java/org/folio/rest/impl/TitlesTestData.java b/src/test/java/org/folio/rest/impl/TitlesTestData.java deleted file mode 100644 index 18758b9ae..000000000 --- a/src/test/java/org/folio/rest/impl/TitlesTestData.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.folio.rest.impl; - -import static org.folio.rest.impl.WireMockTestBase.STUB_CUSTOMER_ID; - -public class TitlesTestData { - public static final String STUB_TITLE_ID = "985846"; - public static final String STUB_TITLE_NAME = "F. Scott Fitzgerald's The Great Gatsby (Great Gatsby)"; - - public static final String STUB_CUSTOM_VENDOR_ID = "123356"; - public static final String STUB_CUSTOM_PACKAGE_ID = "3157070"; - public static final String STUB_CUSTOM_TITLE_ID = "19412030"; - public static final String STUB_CUSTOM_TITLE_NAME = "Test Title"; - - public static final String STUB_MANAGED_TITLE_ID = "762169"; - public static final String STUB_MANAGED_TITLE_ID_2 = "1108525"; - - public static final String CUSTOM_TITLE_ENDPOINT = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_CUSTOM_TITLE_ID; - public static final String CUSTOM_RESOURCE_ENDPOINT = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_CUSTOM_VENDOR_ID + "/packages/" + STUB_CUSTOM_PACKAGE_ID - + "/titles/" + STUB_CUSTOM_TITLE_ID; -} diff --git a/src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java new file mode 100644 index 000000000..2966665cd --- /dev/null +++ b/src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java @@ -0,0 +1,356 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.folio.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.rest.impl.DefaultLoadHoldingsImplIntegrationTest.HOLDINGS_LOAD_BY_ID_URL; +import static org.folio.rest.impl.DefaultLoadHoldingsImplIntegrationTest.assertLatch; +import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; +import static org.folio.service.holdings.HoldingConstants.LOAD_FACADE_ADDRESS; +import static org.folio.service.holdings.HoldingConstants.SAVE_HOLDINGS_ACTION; +import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; +import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_FAILED_ACTION; +import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; +import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.interceptAndContinue; +import static org.folio.util.TestUtil.interceptAndStop; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.result; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.spy; + +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import io.vertx.core.Handler; +import io.vertx.core.eventbus.DeliveryContext; +import io.vertx.core.json.Json; +import io.vertx.core.json.JsonObject; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.function.Function; +import java.util.stream.Collectors; +import lombok.SneakyThrows; +import org.folio.holdingsiq.model.Configuration; +import org.folio.holdingsiq.model.HoldingsDownloadTransaction; +import org.folio.holdingsiq.model.HoldingsTransactionIdsList; +import org.folio.holdingsiq.model.TransactionId; +import org.folio.repository.holdings.DbHoldingInfo; +import org.folio.repository.holdings.status.HoldingsStatusRepositoryImpl; +import org.folio.repository.holdings.status.retry.RetryStatusRepository; +import org.folio.service.holdings.HoldingsService; +import org.folio.service.holdings.LoadServiceFacade; +import org.folio.service.holdings.message.HoldingsMessage; +import org.folio.service.holdings.message.LoadHoldingsMessage; +import org.folio.util.HoldingsTestUtil; +import org.folio.util.IntegrationTestBase; +import org.folio.util.TransactionIdTestUtil; +import org.jspecify.annotations.NonNull; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.util.ReflectionTestUtils; + +@ExtendWith({TransactionLoadHoldingsImplIntegrationTest.SystemPropertyExtension.class}) +class TransactionLoadHoldingsImplIntegrationTest extends IntegrationTestBase { + + private static final String PREVIOUS_TRANSACTION_ID = "abcd3ab0-da4b-4a1f-a004-a9d323e54cde"; + private static final String TRANSACTION_ID = "84113ab0-da4b-4a1f-a004-a9d686e54811"; + private static final String DELTA_ID = "7e3537a0-3f30-4ef8-9470-dd0a87ac1066"; + private static final String DELETED_HOLDING_ID = "123356-3157070-19412030"; + private static final String UPDATED_HOLDING_ID = "123357-3157072-19412032"; + private static final String ADDED_HOLDING_ID = "36-7191-2435667"; + private static final int EXPECTED_LOADED_PAGES = 2; + private static final int TEST_SNAPSHOT_RETRY_COUNT = 2; + private static final String STUB_HOLDINGS_TITLE = "java-test-one"; + + // RM API responses + private static final String RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED = + "responses/rmapi/holdings/status/get-transaction-status-completed.json"; + private static final String RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED_ONE_PAGE = + "responses/rmapi/holdings/status/get-transaction-status-completed-one-page.json"; + private static final String RMAPI_RESPONSE_DELTA_REPORT_STATUS_COMPLETED = + "responses/rmapi/holdings/status/get-delta-report-status-completed.json"; + private static final String RMAPI_RESPONSE_HOLDINGS = + "responses/rmapi/holdings/holdings/get-holdings.json"; + private static final String RMAPI_RESPONSE_DELTA = + "responses/rmapi/holdings/delta/get-delta.json"; + + // KB-EBSCO holdings fixtures + private static final String KB_EBSCO_CUSTOM_HOLDING = + "responses/kb-ebsco/holdings/custom-holding.json"; + private static final String KB_EBSCO_CUSTOM_HOLDING_2 = + "responses/kb-ebsco/holdings/custom-holding2.json"; + + @Autowired + private HoldingsService holdingsService; + @Autowired + private HoldingsStatusRepositoryImpl holdingsStatusRepository; + @Autowired + private RetryStatusRepository retryStatusRepository; + private Configuration configuration; + private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; + + @BeforeEach + void setUp() { + configuration = Configuration.builder() + .apiKey(STUB_API_KEY) + .customerId(STUB_CUSTOMER_ID) + .url(getWiremockUrl()) + .build(); + setupDefaultLoadKbConfiguration(); + + holdingsStatusRepository = spy(holdingsStatusRepository); + ReflectionTestUtils.setField(holdingsService, "holdingsStatusRepository", holdingsStatusRepository); + } + + @AfterEach + void tearDown() { + if (interceptor != null) { + vertx.eventBus().removeOutboundInterceptor(interceptor); + } + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldSaveHoldings() { + runPostHoldingsWithMocks(); + + var holdingsList = HoldingsTestUtil.getHoldings(vertx); + assertFalse(holdingsList.isEmpty()); + } + + @Test + void shouldSaveHoldingsWhenPreviousTransactionExpired() { + TransactionIdTestUtil.addTransactionId(STUB_CREDENTIALS_ID, PREVIOUS_TRANSACTION_ID, vertx); + runPostHoldingsWithMocks(); + + var holdingsList = HoldingsTestUtil.getHoldings(vertx); + assertFalse(holdingsList.isEmpty()); + } + + @Test + @SuppressWarnings("checkstyle:MethodLength") + void shouldUpdateHoldingsWithDeltas() { + HoldingsTestUtil.saveHolding(STUB_CREDENTIALS_ID, + Json.decodeValue(readFile(KB_EBSCO_CUSTOM_HOLDING), DbHoldingInfo.class), + OffsetDateTime.now(), vertx); + HoldingsTestUtil.saveHolding(STUB_CREDENTIALS_ID, + Json.decodeValue(readFile(KB_EBSCO_CUSTOM_HOLDING_2), DbHoldingInfo.class), + OffsetDateTime.now(), vertx); + TransactionIdTestUtil.addTransactionId(STUB_CREDENTIALS_ID, PREVIOUS_TRANSACTION_ID, vertx); + + var previousTransaction = HoldingsDownloadTransaction.builder() + .creationDate(OffsetDateTime.now().minusHours(500).toString()) + .transactionId(PREVIOUS_TRANSACTION_ID) + .build(); + mockTransactionList(singletonList(previousTransaction)); + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), 202); + mockGet(equalTo(transactionStatusRmApi(PREVIOUS_TRANSACTION_ID)), + readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockPost(equalTo(deltasRmApi()), DELTA_ID, 202); + mockGet(equalTo(deltaStatusRmApi(DELTA_ID)), readFile(RMAPI_RESPONSE_DELTA_REPORT_STATUS_COMPLETED)); + mockGet(equalTo(deltaByIdRmApi(DELTA_ID)), readFile(RMAPI_RESPONSE_DELTA)); + + var latch = new CountDownLatch(1); + DefaultLoadHoldingsImplIntegrationTest.handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + + var holdings = HoldingsTestUtil.getHoldings(vertx) + .stream() + .collect(Collectors.toMap(this::getHoldingsId, Function.identity())); + + assertFalse(holdings.containsKey(DELETED_HOLDING_ID)); + + var updatedHolding = holdings.get(UPDATED_HOLDING_ID); + assertEquals("Test Title Updated", updatedHolding.getPublicationTitle()); + assertEquals("Test one Press Updated", updatedHolding.getPublisherName()); + assertEquals("Book", updatedHolding.getResourceType()); + + var addedHolding = holdings.get(ADDED_HOLDING_ID); + assertEquals("Added test title", addedHolding.getPublicationTitle()); + assertEquals("Added test publisher", addedHolding.getPublisherName()); + assertEquals("Book", addedHolding.getResourceType()); + } + + @Test + void shouldRetryCreationOfSnapshotWhenItFails() { + mockEmptyTransactionList(); + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), 202); + var failedResponse = aResponse().withStatus(500); + var successfulResponse = aResponse().withBody(readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockResponseList(urlPathEqualTo(transactionStatusRmApi(TRANSACTION_ID)), + failedResponse, + successfulResponse, + successfulResponse); + + var latch = new CountDownLatch(1); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + } + + @Test + void shouldStopRetryingAfterMultipleFailures() { + mockEmptyTransactionList(); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockPost(equalTo(postTransactionsHoldingsRmApi()), "", 500); + + var latch = new CountDownLatch(TEST_SNAPSHOT_RETRY_COUNT); + interceptor = interceptAndContinue(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_FAILED_ACTION, o -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + + var status = result(retryStatusRepository.findByCredentialsId(UUID.fromString(STUB_CREDENTIALS_ID), STUB_TENANT)); + var timerExists = vertx.cancelTimer(status.getTimerId()); + assertEquals(0, status.getRetryAttemptsLeft()); + assertFalse(timerExists); + + verifyPost(equalTo(postTransactionsHoldingsRmApi()), TEST_SNAPSHOT_RETRY_COUNT); + } + + @Test + void shouldRetryLoadingHoldingsFromStartWhenPageFailsToLoad() { + mockEmptyTransactionList(); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), 202); + + var successResponse = new ResponseDefinitionBuilder() + .withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) + .withStatus(200); + var failResponse = new ResponseDefinitionBuilder().withStatus(500); + mockResponseList(urlPathEqualTo(transactionByIdRmApi(TRANSACTION_ID)), + successResponse, failResponse, failResponse, successResponse); + + var firstTryPages = 1; + var secondTryPages = 2; + var latch = new CountDownLatch(firstTryPages + secondTryPages); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + } + + @Test + void shouldSendSaveHoldingsEventForEachLoadedPage() { + mockEmptyTransactionList(); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockGet(matching(transactionByIdRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_HOLDINGS)); + + var messages = new ArrayList<HoldingsMessage>(); + var latch = new CountDownLatch(EXPECTED_LOADED_PAGES); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, + message -> { + messages.add(((JsonObject) message.body()).getJsonObject("holdings").mapTo(HoldingsMessage.class)); + latch.countDown(); + }); + vertx.eventBus().addOutboundInterceptor(interceptor); + + var proxy = LoadServiceFacade.createProxy(vertx, LOAD_FACADE_ADDRESS); + var message = new LoadHoldingsMessage(this.configuration, STUB_CREDENTIALS_ID, + STUB_TENANT, 5001, 2, TRANSACTION_ID, null); + proxy.loadHoldings(message); + + assertLatch(latch); + assertEquals(2, messages.size()); + assertEquals(STUB_HOLDINGS_TITLE, messages.getFirst().getHoldingList().getFirst().getPublicationTitle()); + } + + @Test + void shouldRetryLoadingPageWhenPageFails() { + mockEmptyTransactionList(); + var latch = new CountDownLatch(1); + DefaultLoadHoldingsImplIntegrationTest.handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), + readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED_ONE_PAGE)); + + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), 202); + mockResponseList(urlPathEqualTo(transactionByIdRmApi(TRANSACTION_ID)), + new ResponseDefinitionBuilder().withStatus(SC_INTERNAL_SERVER_ERROR), + new ResponseDefinitionBuilder().withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) + ); + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + assertLatch(latch); + } + + private void setupDefaultLoadKbConfiguration() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); + insertRetryStatus(STUB_CREDENTIALS_ID, vertx); + } + + @SneakyThrows + private void runPostHoldingsWithMocks() { + var latch = new CountDownLatch(1); + DefaultLoadHoldingsImplIntegrationTest.handleStatusCompleted(holdingsStatusRepository, o -> latch.countDown()); + + mockEmptyTransactionList(); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), 202); + mockGet(matching(transactionByIdRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_HOLDINGS)); + + postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT); + + assertLatch(latch); + } + + private void mockEmptyTransactionList() { + mockTransactionList(emptyList()); + } + + private void mockTransactionList(List<HoldingsDownloadTransaction> transactionIds) { + var transactionList = + HoldingsTransactionIdsList.builder().holdingsDownloadTransactionIds(transactionIds).build(); + mockGet(equalTo(transactionsRmApi()), Json.encode(transactionList)); + } + + private TransactionId createTransactionId() { + return TransactionId.builder().transactionId(TRANSACTION_ID).build(); + } + + private String getHoldingsId(DbHoldingInfo holding) { + return holding.getVendorId() + "-" + holding.getPackageId() + "-" + holding.getTitleId(); + } + + public static class SystemPropertyExtension + implements BeforeAllCallback, AfterAllCallback { + + @Override + public void beforeAll(@NonNull ExtensionContext context) { + System.setProperty("holdings.load.implementation.qualifier", "transactionLoadServiceFacade"); + } + + @Override + public void afterAll(@NonNull ExtensionContext context) { + System.clearProperty("holdings.load.implementation.qualifier"); + } + } +} diff --git a/src/test/java/org/folio/rest/impl/TransactionLoadServiceFacadeIntegrationTest.java b/src/test/java/org/folio/rest/impl/TransactionLoadServiceFacadeIntegrationTest.java new file mode 100644 index 000000000..ad2e5c52c --- /dev/null +++ b/src/test/java/org/folio/rest/impl/TransactionLoadServiceFacadeIntegrationTest.java @@ -0,0 +1,145 @@ +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static org.folio.HttpStatus.SC_ACCEPTED; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.service.holdings.AbstractLoadServiceFacade.HOLDINGS_STATUS_TIME_FORMATTER; +import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; +import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; +import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; +import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; +import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.interceptAndStop; +import static org.folio.util.TestUtil.readFile; +import static org.folio.util.TestUtil.readJsonFile; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.vertx.core.Handler; +import io.vertx.core.eventbus.DeliveryContext; +import io.vertx.core.json.Json; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.folio.holdingsiq.model.Configuration; +import org.folio.holdingsiq.model.HoldingsLoadTransactionStatus; +import org.folio.holdingsiq.model.HoldingsTransactionIdsList; +import org.folio.holdingsiq.model.TransactionId; +import org.folio.service.holdings.TransactionLoadServiceFacade; +import org.folio.service.holdings.message.ConfigurationMessage; +import org.folio.service.holdings.message.LoadHoldingsMessage; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class TransactionLoadServiceFacadeIntegrationTest extends IntegrationTestBase { + + private static final String TRANSACTION_ID = "84113ab0-da4b-4a1f-a004-a9d686e54811"; + private static final int TIMEOUT = 60000; + + // RM API responses + private static final String RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED = + "responses/rmapi/holdings/status/get-transaction-status-completed.json"; + private static final String RMAPI_RESPONSE_TRANSACTION_LIST_IN_PROGRESS = + "responses/rmapi/holdings/status/get-transaction-list-in-progress.json"; + private static final String RMAPI_RESPONSE_TRANSACTION_LIST = + "responses/rmapi/holdings/status/get-transaction-list.json"; + + @Autowired + private TransactionLoadServiceFacade loadServiceFacade; + + private Configuration stubConfiguration; + private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; + + @BeforeEach + void setUp() { + stubConfiguration = Configuration.builder() + .apiKey(STUB_API_KEY) + .customerId(STUB_CUSTOMER_ID) + .url(getWiremockUrl()) + .build(); + setupDefaultLoadKbConfiguration(); + } + + @AfterEach + void tearDown() { + if (interceptor != null) { + vertx.eventBus().removeOutboundInterceptor(interceptor); + } + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @Test + void shouldCreateSnapshotOnInitialStatusNone() throws Exception { + mockEmptyTransactionList(); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), SC_ACCEPTED); + + var latch = new CountDownLatch(1); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + loadServiceFacade.createSnapshot(new ConfigurationMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT)); + + assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } + + @Test + void shouldCreateSnapshotUsingExistingTransactionIfItIsInProgress() throws Exception { + mockGet(equalTo(transactionsRmApi()), readFile(RMAPI_RESPONSE_TRANSACTION_LIST_IN_PROGRESS)); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), SC_ACCEPTED); + + var latch = new CountDownLatch(1); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + loadServiceFacade.createSnapshot(new ConfigurationMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT)); + + assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } + + @Test + void shouldNotCreateSnapshotIfItWasRecentlyCreated() throws Exception { + var now = HOLDINGS_STATUS_TIME_FORMATTER.format(LocalDateTime.now(ZoneOffset.UTC)); + var idList = readJsonFile(RMAPI_RESPONSE_TRANSACTION_LIST, HoldingsTransactionIdsList.class); + var firstTransaction = idList.getHoldingsDownloadTransactionIds().getFirst(); + idList.getHoldingsDownloadTransactionIds().set(0, firstTransaction.toBuilder().creationDate(now).build()); + var status = readJsonFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED, HoldingsLoadTransactionStatus.class) + .toBuilder().creationDate(now).build(); + mockGet(equalTo(transactionsRmApi()), Json.encode(idList)); + mockGet(equalTo(transactionStatusRmApi(TRANSACTION_ID)), Json.encode(status)); + mockPost(equalTo(postTransactionsHoldingsRmApi()), Json.encode(createTransactionId()), SC_ACCEPTED); + + var latch = new CountDownLatch(1); + interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> latch.countDown()); + vertx.eventBus().addOutboundInterceptor(interceptor); + + loadServiceFacade.createSnapshot(new ConfigurationMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT)); + + latch.await(TIMEOUT, TimeUnit.MILLISECONDS); + + verifyPost(equalTo(postTransactionsHoldingsRmApi()), 0); + } + + private void mockEmptyTransactionList() { + var transactionList = HoldingsTransactionIdsList.builder() + .holdingsDownloadTransactionIds(Collections.emptyList()).build(); + mockGet(equalTo(transactionsRmApi()), Json.encode(transactionList)); + } + + private TransactionId createTransactionId() { + return TransactionId.builder().transactionId(TRANSACTION_ID).build(); + } + + private void setupDefaultLoadKbConfiguration() { + saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); + saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); + insertRetryStatus(STUB_CREDENTIALS_ID, vertx); + } +} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/UsageConsolidationCredentialsApiTest.java b/src/test/java/org/folio/rest/impl/UsageConsolidationCredentialsApiIntegrationTest.java similarity index 51% rename from src/test/java/org/folio/rest/impl/integrationsuite/UsageConsolidationCredentialsApiTest.java rename to src/test/java/org/folio/rest/impl/UsageConsolidationCredentialsApiIntegrationTest.java index 584528683..7ef2f3f80 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/UsageConsolidationCredentialsApiTest.java +++ b/src/test/java/org/folio/rest/impl/UsageConsolidationCredentialsApiIntegrationTest.java @@ -1,65 +1,45 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; +package org.folio.rest.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNPROCESSABLE_CONTENT; import static org.folio.repository.uc.UcCredentialsTableConstants.UC_CREDENTIALS_TABLE_NAME; import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbTestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.clearDataFromTable; import static org.folio.util.UcCredentialsTestUtil.STUB_CLIENT_ID; import static org.folio.util.UcCredentialsTestUtil.STUB_CLIENT_SECRET; import static org.folio.util.UcCredentialsTestUtil.UC_CREDENTIALS_ENDPOINT; import static org.folio.util.UcCredentialsTestUtil.getUcCredentials; import static org.folio.util.UcCredentialsTestUtil.setUpUcCredentials; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import com.github.tomakehurst.wiremock.matching.AnythingPattern; import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.folio.client.uc.UcAuthEbscoClient; import org.folio.client.uc.model.UcAuthToken; -import org.folio.rest.impl.WireMockTestBase; import org.folio.rest.jaxrs.model.JsonapiError; import org.folio.rest.jaxrs.model.UCCredentials; import org.folio.rest.jaxrs.model.UCCredentialsAttributes; import org.folio.rest.jaxrs.model.UCCredentialsClientId; import org.folio.rest.jaxrs.model.UCCredentialsClientSecret; import org.folio.rest.jaxrs.model.UCCredentialsPresence; -import org.json.JSONException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.folio.util.IntegrationTestBase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.util.ReflectionTestUtils; - -@RunWith(VertxUnitRunner.class) -public class UsageConsolidationCredentialsApiTest extends WireMockTestBase { - @Autowired - private UcAuthEbscoClient authEbscoClient; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - ReflectionTestUtils.setField(authEbscoClient, "baseUrl", getWiremockUrl()); - } +class UsageConsolidationCredentialsApiIntegrationTest extends IntegrationTestBase { - @After - public void tearDown() { + @AfterEach + void tearDown() { clearDataFromTable(vertx, UC_CREDENTIALS_TABLE_NAME); } @Test - public void shouldReturnUcCredentialsPresenceWithTrueOnGetWhenCredentialsExists() { + void shouldReturnUcCredentialsPresenceWithTrueOnGetWhenCredentialsExists() { setUpUcCredentials(vertx); var actual = getWithOk(UC_CREDENTIALS_ENDPOINT).as(UCCredentialsPresence.class); @@ -68,17 +48,17 @@ public void shouldReturnUcCredentialsPresenceWithTrueOnGetWhenCredentialsExists( } @Test - public void shouldReturnUcCredentialsPresenceWithFalseOnGetWhenCredentialsNotExist() { + void shouldReturnUcCredentialsPresenceWithFalseOnGetWhenCredentialsNotExist() { var actual = getWithOk(UC_CREDENTIALS_ENDPOINT).as(UCCredentialsPresence.class); assertFalse(actual.getAttributes().getIsPresent()); } @Test - public void shouldSaveNewValidUcCredentials() { + void shouldSaveNewValidUcCredentials() { mockAuthToken(SC_OK); - String requestBody = getRequestBody(STUB_CLIENT_ID, STUB_CLIENT_SECRET); + var requestBody = getRequestBody(STUB_CLIENT_ID, STUB_CLIENT_SECRET); putWithNoContent(UC_CREDENTIALS_ENDPOINT, requestBody); var actualCredentials = getUcCredentials(vertx); @@ -88,11 +68,11 @@ public void shouldSaveNewValidUcCredentials() { } @Test - public void shouldSaveNewInvalidUcCredentials() { + void shouldSaveNewInvalidUcCredentials() { mockAuthToken(SC_BAD_REQUEST); - String requestBody = getRequestBody(STUB_CLIENT_ID, STUB_CLIENT_SECRET); - var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var requestBody = getRequestBody(STUB_CLIENT_ID, STUB_CLIENT_SECRET); + var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); var actualCredentials = getUcCredentials(vertx); @@ -101,13 +81,13 @@ public void shouldSaveNewInvalidUcCredentials() { } @Test - public void shouldUpdateExistingWithNewValidUcCredentials() { + void shouldUpdateExistingWithNewValidUcCredentials() { setUpUcCredentials(vertx); mockAuthToken(SC_OK); var newClientId = "NEW_ID"; var newClientSecret = "NEW_TOKEN"; - String requestBody = getRequestBody(newClientId, newClientSecret); + var requestBody = getRequestBody(newClientId, newClientSecret); putWithNoContent(UC_CREDENTIALS_ENDPOINT, requestBody); var actualCredentials = getUcCredentials(vertx); @@ -117,38 +97,37 @@ public void shouldUpdateExistingWithNewValidUcCredentials() { } @Test - public void shouldNotUpdateExistingWithNewInvalidUcCredentials() { + void shouldNotUpdateExistingWithNewInvalidUcCredentials() { setUpUcCredentials(vertx); mockAuthToken(SC_BAD_REQUEST); var newClientId = "NEW_ID"; var newClientSecret = "NEW_TOKEN"; - String requestBody = getRequestBody(newClientId, newClientSecret); - var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); - + var requestBody = getRequestBody(newClientId, newClientSecret); + var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid Usage Consolidation Credentials"); - var actualCredentials = getUcCredentials(vertx); + var actualCredentials = getUcCredentials(vertx); assertEquals(STUB_CLIENT_ID, actualCredentials.clientId()); assertEquals(STUB_CLIENT_SECRET, actualCredentials.clientSecret()); } @Test - public void shouldReturn200OnGetUcCredentialsClientId() throws JSONException { + void shouldReturn200OnGetUcCredentialsClientId() throws Exception { setUpUcCredentials(vertx); - String actualResponse = getWithOk(UC_CREDENTIALS_ENDPOINT + "/clientId").asString(); + var actualResponse = getWithOk(UC_CREDENTIALS_ENDPOINT + "/clientId").asString(); - JSONAssert.assertEquals(getClientIdJsonBody(STUB_CLIENT_ID), actualResponse, false); + JSONAssert.assertEquals(getClientIdJsonBody(), actualResponse, false); } @Test - public void shouldReturn200OnGetUcCredentialsClientSecret() throws JSONException { + void shouldReturn200OnGetUcCredentialsClientSecret() throws Exception { setUpUcCredentials(vertx); - String actualResponse = getWithOk(UC_CREDENTIALS_ENDPOINT + "/clientSecret").asString(); + var actualResponse = getWithOk(UC_CREDENTIALS_ENDPOINT + "/clientSecret").asString(); - JSONAssert.assertEquals(getClientSecretJsonBody(STUB_CLIENT_SECRET), actualResponse, false); + JSONAssert.assertEquals(getClientSecretJsonBody(), actualResponse, false); } private String getRequestBody(String clientId, String clientSecret) { @@ -161,22 +140,20 @@ private String getRequestBody(String clientId, String clientSecret) { return Json.encode(credentials); } - private String getClientIdJsonBody(String clientId) { + private String getClientIdJsonBody() { var ucCredentialsClientId = new UCCredentialsClientId() - .withClientId(clientId); + .withClientId(STUB_CLIENT_ID); return Json.encode(ucCredentialsClientId); } - private String getClientSecretJsonBody(String clientSecret) { + private String getClientSecretJsonBody() { var ucCredentialsClientSecret = new UCCredentialsClientSecret() - .withClientSecret(clientSecret); + .withClientSecret(STUB_CLIENT_SECRET); return Json.encode(ucCredentialsClientSecret); } private void mockAuthToken(int status) { - UcAuthToken stubToken = new UcAuthToken("access_token", "Bearer", 3600L, "openid"); - stubFor(post(urlPathMatching("/oauth-proxy/token")) - .willReturn(aResponse().withStatus(status).withBody(Json.encode(stubToken))) - ); + var stubToken = new UcAuthToken("access_token", "Bearer", 3600L, "openid"); + mockPost(equalTo("/oauth-proxy/token"), new AnythingPattern(), Json.encode(stubToken), status); } } diff --git a/src/test/java/org/folio/rest/impl/WireMockTestBase.java b/src/test/java/org/folio/rest/impl/WireMockTestBase.java deleted file mode 100644 index 48de280c1..000000000 --- a/src/test/java/org/folio/rest/impl/WireMockTestBase.java +++ /dev/null @@ -1,256 +0,0 @@ -package org.folio.rest.impl; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.badRequest; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.ok; -import static com.github.tomakehurst.wiremock.client.WireMock.serverError; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static io.restassured.RestAssured.given; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_CREATED; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_OK; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.util.RestConstants.JSON_API_TYPE; -import static org.folio.service.locale.LocaleSettingsServiceImpl.LOCALE_ENDPOINT_PATH; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.hamcrest.Matchers.notNullValue; - -import com.github.tomakehurst.wiremock.http.Fault; -import io.restassured.RestAssured; -import io.restassured.http.Header; -import io.restassured.http.Headers; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -import io.vertx.ext.unit.TestContext; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import lombok.SneakyThrows; -import org.apache.http.HttpStatus; -import org.apache.http.protocol.HTTP; -import org.folio.cache.VertxCache; -import org.folio.config.cache.VendorIdCacheKey; -import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.PackageByIdData; -import org.folio.holdingsiq.model.Title; -import org.folio.holdingsiq.model.VendorById; -import org.folio.okapi.common.XOkapiHeaders; -import org.folio.rmapi.cache.PackageCacheKey; -import org.folio.rmapi.cache.ResourceCacheKey; -import org.folio.rmapi.cache.TitleCacheKey; -import org.folio.rmapi.cache.VendorCacheKey; -import org.folio.spring.SpringContextUtil; -import org.folio.test.util.TestBase; -import org.junit.Before; -import org.junit.BeforeClass; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -/** - * Base test class for tests that use wiremock and vertx http servers, - * test that inherits this class must use VertxUnitRunner as test runner. - */ -public abstract class WireMockTestBase extends TestBase { - - public static final String JOHN_ID = "47d9ca93-9c82-4d6a-8d7f-7a73963086b9"; - public static final String JOHN_GROUP_ID = "b4b5e97a-0a99-4db9-97df-4fdf406ec74d"; - public static final String JOHN_USERNAME = "john_doe"; - public static final Header JOHN_USER_ID_HEADER = new Header(XOkapiHeaders.USER_ID, JOHN_ID); - public static final String JANE_ID = "781fce7d-5cf5-490d-ad89-a3d192eb526c"; - public static final String JANE_GROUP_ID = "4bb563d9-3f9d-4e1e-8d1d-04e75666d68f"; - public static final String JANE_USERNAME = "jane_doe"; - public static final Header JANE_USER_ID_HEADER = new Header(XOkapiHeaders.USER_ID, JANE_ID); - - protected static final Header CONTENT_TYPE_HEADER = new Header(HTTP.CONTENT_TYPE, JSON_API_TYPE); - protected static final String STUB_CUSTOMER_ID = "TEST_CUSTOMER_ID"; - protected static final String STUB_API_KEY = "TEST_API_KEY"; - protected static final String STUB_CREDENTIALS_ID = "12312312-1231-1231-a111-111111111111"; - - @Autowired - @Qualifier("rmApiConfigurationCache") - private VertxCache<String, Configuration> configurationCache; - @Autowired - @Qualifier("vendorIdCache") - private VertxCache<VendorIdCacheKey, Long> vendorIdCache; - @Autowired - private VertxCache<PackageCacheKey, PackageByIdData> packageCache; - @Autowired - private VertxCache<VendorCacheKey, VendorById> vendorCache; - @Autowired - private VertxCache<ResourceCacheKey, Title> resourceCache; - @Autowired - private VertxCache<TitleCacheKey, Title> titleCache; - @Autowired - private VertxCache<String, String> ucTokenCache; - - @BeforeClass - public static void setUpClass(TestContext context) { - configProperties.put("spring.configuration", "org.folio.spring.config.TestConfig"); - TestBase.setUpClass(context); - - // An ad-hoc to clear any records after DB setup but before test execution - // this should be removed once a proper separation between migration scripts and clean DB is in place - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Before - public void setUp() throws Exception { - SpringContextUtil.autowireDependenciesFromFirstContext(this, vertx); - configurationCache.invalidateAll(); - vendorIdCache.invalidateAll(); - packageCache.invalidateAll(); - vendorCache.invalidateAll(); - resourceCache.invalidateAll(); - titleCache.invalidateAll(); - ucTokenCache.invalidateAll(); - } - - protected ExtractableResponse<Response> getWithOk(String endpoint, Header... headers) { - return getWithStatus(endpoint, HttpStatus.SC_OK, headers); - } - - protected ExtractableResponse<Response> getWithStatus(String endpoint, int code, Header... headers) { - return given() - .spec(this.getRequestSpecification()) - .headers(new Headers(headers)) - .when() - .get(endpoint) - .then() - .log() - .ifValidationFails() - .statusCode(code) - .extract(); - } - - protected ExtractableResponse<Response> putWithOk(String endpoint, String putBody) { - return putWithStatus(endpoint, putBody, SC_OK, CONTENT_TYPE_HEADER); - } - - protected ExtractableResponse<Response> putWithOk(String endpoint, String putBody, Header... headers) { - return super.putWithStatus(endpoint, putBody, SC_OK, addContentHeader(headers)); - } - - protected ExtractableResponse<Response> postWithOk(String endpoint, String postBody) { - return postWithStatus(endpoint, postBody, SC_OK, CONTENT_TYPE_HEADER); - } - - protected ExtractableResponse<Response> postWithOk(String endpoint, String postBody, Header... headers) { - return postWithStatus(endpoint, postBody, SC_OK, addContentHeader(headers)); - } - - protected ExtractableResponse<Response> postWithCreated(String endpoint, String postBody) { - return postWithStatus(endpoint, postBody, SC_CREATED, CONTENT_TYPE_HEADER); - } - - protected ExtractableResponse<Response> postWithCreated(String endpoint, String postBody, Header... headers) { - return postWithStatus(endpoint, postBody, SC_CREATED, addContentHeader(headers)); - } - - @Override - protected ExtractableResponse<Response> putWithNoContent(String resourcePath, String putBody, Header... headers) { - return super.putWithNoContent(resourcePath, putBody, addContentHeader(headers)); - } - - @Override - protected ExtractableResponse<Response> putWithStatus(String resourcePath, String putBody, int expectedStatus, - Header... headers) { - return super.putWithStatus(resourcePath, putBody, expectedStatus, addContentHeader(headers)); - } - - @Override - protected ExtractableResponse<Response> postWithStatus(String resourcePath, String postBody, int expectedStatus, - Header... headers) { - return super.postWithStatus(resourcePath, postBody, expectedStatus, addContentHeader(headers)); - } - - protected ExtractableResponse<Response> patchWithNoContent(String resourcePath, String patchBody, Header... headers) { - return patchWithStatus(resourcePath, patchBody, SC_NO_CONTENT, headers); - } - - protected ExtractableResponse<Response> patchWithStatus(String resourcePath, String patchBody, int expectedStatus, - Header... headers) { - return given() - .spec(getRequestSpecification()) - .header(JSON_CONTENT_TYPE_HEADER) - .headers(new Headers(addContentHeader(headers))) - .body(patchBody) - .when() - .patch(resourcePath) - .then() - .log().ifValidationFails() - .statusCode(expectedStatus) - .extract(); - } - - protected ExtractableResponse<Response> deleteWithNoContent(String resourcePath, Header... headers) { - return deleteWithStatus(resourcePath, HttpStatus.SC_NO_CONTENT, headers); - } - - protected ExtractableResponse<Response> deleteWithStatus(String resourcePath, int expectedStatus, Header... headers) { - return given() - .spec(getRequestSpecification()) - .headers(new Headers(headers)) - .when() - .delete(resourcePath) - .then() - .log().ifValidationFails() - .statusCode(expectedStatus) - .extract(); - } - - protected void checkResponseNotEmptyWhenStatusIs400(String path) { - RestAssured.given() - .spec(getRequestSpecification()) - .when() - .get(path) - .then() - .statusCode(SC_BAD_REQUEST) - .body("errors.first.title", notNullValue()); - } - - protected void mockSuccessfulLocaleResponse() { - mockSuccessfulLocaleResponse("responses/configuration/locale-settings.json"); - } - - @SneakyThrows - protected void mockSuccessfulLocaleResponse(String configFileName) { - stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) - .willReturn(ok(readFile(configFileName)))); - } - - @SneakyThrows - protected void mockFailedLocaleResponse() { - stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) - .willReturn(badRequest())); - } - - protected void mockLocaleResponseWithInvalidJson() { - stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) - .willReturn(ok("{ invalid json }"))); - } - - protected void mockLocaleResponseWithEmptyBody() { - stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) - .willReturn(ok())); - } - - protected void mockLocaleResponseWithServerError() { - stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) - .willReturn(serverError())); - } - - protected void mockLocaleResponseWithNetworkError() { - stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) - .willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER))); - } - - private Header[] addContentHeader(Header[] headers) { - List<Header> headerList = new ArrayList<>(Arrays.asList(headers)); - headerList.add(CONTENT_TYPE_HEADER); - return headerList.toArray(new Header[0]); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadHoldingsImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadHoldingsImplTest.java deleted file mode 100644 index b7e3c26bc..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadHoldingsImplTest.java +++ /dev/null @@ -1,530 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.apache.http.HttpStatus.SC_CONFLICT; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.folio.repository.holdings.status.HoldingsLoadingStatusFactory.getStatusCompleted; -import static org.folio.repository.holdings.status.HoldingsLoadingStatusFactory.getStatusLoadingHoldings; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.RmApiConstants.RMAPI_HOLDINGS_STATUS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_POST_HOLDINGS_URL; -import static org.folio.rest.jaxrs.model.LoadStatusNameEnum.COMPLETED; -import static org.folio.rest.util.DateTimeUtil.POSTGRES_TIMESTAMP_FORMATTER; -import static org.folio.rest.util.DateTimeUtil.POSTGRES_TIMESTAMP_OLD_FORMATTER; -import static org.folio.service.holdings.HoldingConstants.CREATE_SNAPSHOT_ACTION; -import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.LOAD_FACADE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.SAVE_HOLDINGS_ACTION; -import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; -import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_FAILED_ACTION; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.mockResponseList; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; -import static org.folio.util.HoldingsStatusAuditTestUtil.saveStatusAudit; -import static org.folio.util.HoldingsStatusUtil.PROCESS_ID; -import static org.folio.util.HoldingsStatusUtil.saveStatus; -import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.interceptAndContinue; -import static org.folio.util.KbTestUtil.interceptAndStop; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasProperty; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.doAnswer; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.http.RequestMethod; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; -import com.github.tomakehurst.wiremock.matching.StringValuePattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.core.Handler; -import io.vertx.core.eventbus.DeliveryContext; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import org.folio.holdingsiq.model.Configuration; -import org.folio.repository.holdings.DbHoldingInfo; -import org.folio.repository.holdings.status.HoldingsStatusRepositoryImpl; -import org.folio.repository.holdings.status.retry.RetryStatusRepository; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.HoldingsLoadingStatus; -import org.folio.rest.jaxrs.model.LoadStatusAttributes; -import org.folio.rest.jaxrs.model.LoadStatusNameDetailEnum; -import org.folio.rest.jaxrs.model.LoadStatusNameEnum; -import org.folio.service.holdings.HoldingsService; -import org.folio.service.holdings.LoadServiceFacade; -import org.folio.service.holdings.message.HoldingsMessage; -import org.folio.service.holdings.message.LoadHoldingsMessage; -import org.folio.util.HoldingsStatusAuditTestUtil; -import org.folio.util.HoldingsStatusUtil; -import org.folio.util.HoldingsTestUtil; -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; -import org.springframework.beans.factory.annotation.Autowired; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class DefaultLoadHoldingsImplTest extends WireMockTestBase { - - public static final String HOLDINGS_LOAD_URL = "/eholdings/loading/kb-credentials"; - public static final String HOLDINGS_LOAD_BY_ID_URL = HOLDINGS_LOAD_URL + "/" + STUB_CREDENTIALS_ID; - public static final String RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED = - "responses/rmapi/holdings/status/get-status-completed.json"; - public static final String RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED_ONE_PAGE = - "responses/rmapi/holdings/status/get-status-completed-one-page.json"; - public static final String RMAPI_RESPONSE_HOLDINGS = "responses/rmapi/holdings/holdings/get-holdings.json"; - private static final int TIMEOUT = 180000; - private static final int EXPECTED_LOADED_PAGES = 2; - private static final int TEST_SNAPSHOT_RETRY_COUNT = 2; - private static final String STUB_HOLDINGS_TITLE = "java-test-one"; - @InjectMocks - @Autowired - HoldingsService holdingsService; - @Spy - @Autowired - HoldingsStatusRepositoryImpl holdingsStatusRepository; - @Autowired - RetryStatusRepository retryStatusRepository; - private Configuration stubConfiguration; - private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; - - @BeforeClass - public static void setUpClass(TestContext context) { - WireMockTestBase.setUpClass(context); - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - MockitoAnnotations.openMocks(this).close(); - stubConfiguration = Configuration.builder() - .apiKey(STUB_API_KEY) - .customerId(STUB_CUSTOMER_ID) - .url(getWiremockUrl()) - .build(); - } - - @After - public void tearDown() { - if (interceptor != null) { - vertx.eventBus().removeOutboundInterceptor(interceptor); - } - tearDownHoldingsData(); - } - - @Test - public void shouldSaveHoldings(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - runPostHoldingsWithMocks(context); - - final List<DbHoldingInfo> holdingsList = HoldingsTestUtil.getHoldings(vertx); - assertThat(holdingsList.size(), Matchers.notNullValue()); - } - - @Test - public void shouldSaveMultiHoldings(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED); - mockPostHoldings(); - mockGet(new RegexPattern(RMAPI_POST_HOLDINGS_URL), RMAPI_RESPONSE_HOLDINGS); - - postWithStatus(HOLDINGS_LOAD_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - - final List<DbHoldingInfo> holdingsList = HoldingsTestUtil.getHoldings(vertx); - assertThat(holdingsList.size(), Matchers.notNullValue()); - } - - @Test - public void shouldSaveMultiHoldingsWhenSnapshotNotCreated(TestContext context) - throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - - ResponseDefinitionBuilder errorResponse = new ResponseDefinitionBuilder() - .withStatus(500); - ResponseDefinitionBuilder emptyResponse = new ResponseDefinitionBuilder() - .withBody(""); - ResponseDefinitionBuilder successfulResponse = new ResponseDefinitionBuilder() - .withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); - - mockResponseList(new UrlPathPattern(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), false), - errorResponse, - emptyResponse, - successfulResponse); - - mockPostHoldings(); - mockGet(new RegexPattern(RMAPI_POST_HOLDINGS_URL), RMAPI_RESPONSE_HOLDINGS); - - postWithStatus(HOLDINGS_LOAD_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - - final List<DbHoldingInfo> holdingsList = HoldingsTestUtil.getHoldings(vertx); - assertThat(holdingsList.size(), Matchers.notNullValue()); - } - - @Test - public void shouldNotStartLoadingWhenStatusInProgress() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveStatus(STUB_CREDENTIALS_ID, getStatusLoadingHoldings(1000, 500, 10, 5), PROCESS_ID, vertx); - interceptor = interceptAndStop(LOAD_FACADE_ADDRESS, CREATE_SNAPSHOT_ACTION, message -> { }); - vertx.eventBus().addOutboundInterceptor(interceptor); - var statusCode = postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_CONFLICT, STUB_USER_ID_HEADER).statusCode(); - assertEquals(SC_CONFLICT, statusCode); - } - - @Test - public void shouldStartLoadingWithOldDateFormat(TestContext context) throws IOException, URISyntaxException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - OffsetDateTime dateTime = OffsetDateTime.now().minusDays(6); - HoldingsLoadingStatus status = getStatusLoadingHoldings(1000, 500, 10, 5); - status.getData().getAttributes().setStarted(dateTime.format(POSTGRES_TIMESTAMP_OLD_FORMATTER)); - status.getData().getAttributes().setUpdated(dateTime.format(POSTGRES_TIMESTAMP_OLD_FORMATTER)); - saveStatus(STUB_CREDENTIALS_ID, status, PROCESS_ID, vertx); - - insertRetryStatus(STUB_CREDENTIALS_ID, vertx); - runPostHoldingsWithMocks(context); - - final List<DbHoldingInfo> holdingsList = HoldingsTestUtil.getHoldings(vertx); - assertThat(holdingsList.size(), Matchers.notNullValue()); - } - - @Test - public void shouldStartLoadingWhenStatusInProgressAndStartedMoreThen5DaysBefore(TestContext context) - throws IOException, URISyntaxException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - OffsetDateTime dateTime = OffsetDateTime.now().minusDays(6); - HoldingsLoadingStatus statusLoadingHoldings = getStatusLoadingHoldings(1000, 500, 10, 5); - statusLoadingHoldings.getData().getAttributes().setStarted(dateTime.format(POSTGRES_TIMESTAMP_FORMATTER)); - statusLoadingHoldings.getData().getAttributes().setUpdated(dateTime.format(POSTGRES_TIMESTAMP_FORMATTER)); - saveStatus(STUB_CREDENTIALS_ID, statusLoadingHoldings, PROCESS_ID, dateTime, vertx); - - insertRetryStatus(STUB_CREDENTIALS_ID, vertx); - runPostHoldingsWithMocks(context); - - final List<DbHoldingInfo> holdingsList = HoldingsTestUtil.getHoldings(vertx); - assertThat(holdingsList.size(), Matchers.notNullValue()); - } - - @Test - public void shouldSaveStatusChangesToAuditTable(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - - runPostHoldingsWithMocks(context); - List<LoadStatusAttributes> attributes = HoldingsStatusAuditTestUtil.getRecords(vertx) - .stream().map(status -> status.getData().getAttributes()).toList(); - - assertThat(attributes, containsInAnyOrder( - statusEquals(LoadStatusNameEnum.NOT_STARTED), - statusEquals(LoadStatusNameEnum.NOT_STARTED), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 0), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 1), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 2), - statusEquals(LoadStatusNameEnum.COMPLETED) - ) - ); - } - - @Test - public void shouldClearOldStatusChangeRecords() { - setupDefaultLoadKbConfiguration(); - saveStatusAudit(STUB_CREDENTIALS_ID, getStatusCompleted(1000), - OffsetDateTime.now().minusDays(60), vertx); - - interceptor = interceptAndStop(LOAD_FACADE_ADDRESS, CREATE_SNAPSHOT_ACTION, message -> { }); - vertx.eventBus().addOutboundInterceptor(interceptor); - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - List<LoadStatusAttributes> attributes = HoldingsStatusAuditTestUtil.getRecords(vertx) - .stream().map(status -> status.getData().getAttributes()).toList(); - assertEquals(3, attributes.size()); - assertThat(attributes, containsInAnyOrder( - statusEquals(LoadStatusNameEnum.NOT_STARTED), //insert - statusEquals(LoadStatusNameEnum.NOT_STARTED), //delete - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null) - )); - } - - @Test - public void shouldStartLoadingWhenStatusInProgressAndProcessTimedOut() { - setupDefaultLoadKbConfiguration(); - HoldingsLoadingStatus status = getStatusLoadingHoldings(1000, 500, 10, 5); - - OffsetDateTime dateTime = OffsetDateTime.now().minusDays(10); - status.getData().getAttributes().setUpdated(POSTGRES_TIMESTAMP_FORMATTER.format(dateTime)); - saveStatus(STUB_CREDENTIALS_ID, status, PROCESS_ID, vertx); - - interceptor = interceptAndStop(LOAD_FACADE_ADDRESS, CREATE_SNAPSHOT_ACTION, message -> { }); - vertx.eventBus().addOutboundInterceptor(interceptor); - var statusCode = postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER).statusCode(); - assertEquals(SC_NO_CONTENT, statusCode); - } - - @Test - public void shouldRetryCreationOfSnapshotWhenItFails(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - - stubFor( - post(new UrlPathPattern(new EqualToPattern(RMAPI_POST_HOLDINGS_URL), false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody("") - .withStatus(202))); - ResponseDefinitionBuilder failedResponse = new ResponseDefinitionBuilder().withStatus(500); - ResponseDefinitionBuilder successfulResponse = new ResponseDefinitionBuilder() - .withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED)); - mockResponseList(new UrlPathPattern(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), false), - failedResponse, - successfulResponse, - successfulResponse); - - Async async = context.async(); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> async.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - public void shouldStopRetryingAfterMultipleFailures(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED); - - UrlPathPattern urlPattern = new UrlPathPattern(new EqualToPattern(RMAPI_POST_HOLDINGS_URL), false); - stubFor( - post(urlPattern) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(500))); - - Async async = context.async(TEST_SNAPSHOT_RETRY_COUNT); - interceptor = interceptAndContinue(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_FAILED_ACTION, o -> async.countDown()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - - Async retryStatusAsync = context.async(); - retryStatusRepository.findByCredentialsId(UUID.fromString(STUB_CREDENTIALS_ID), STUB_TENANT) - .thenAccept(status -> { - boolean timerExists = vertx.cancelTimer(status.getTimerId()); - context.assertEquals(0, status.getRetryAttemptsLeft()); - context.assertFalse(timerExists); - retryStatusAsync.complete(); - }); - retryStatusAsync.await(TIMEOUT); - - verify(TEST_SNAPSHOT_RETRY_COUNT, - RequestPatternBuilder.newRequestPattern(RequestMethod.POST, urlPattern)); - } - - @Test - public void shouldRetryLoadingHoldingsFromStartWhenPageFailsToLoad(TestContext context) - throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED); - - stubFor(post(urlPathEqualTo(RMAPI_POST_HOLDINGS_URL)) - .willReturn(new ResponseDefinitionBuilder() - .withBody("") - .withStatus(202))); - - ResponseDefinitionBuilder successResponse = new ResponseDefinitionBuilder() - .withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) - .withStatus(200); - ResponseDefinitionBuilder failResponse = new ResponseDefinitionBuilder().withStatus(500); - mockResponseList(urlPathEqualTo(RMAPI_POST_HOLDINGS_URL), successResponse, failResponse, failResponse, - successResponse); - - int firstTryPages = 1; - int secondTryPages = 2; - Async async = context.async(firstTryPages + secondTryPages); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, message -> async.countDown()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - public void shouldSendSaveHoldingsEventForEachLoadedPage(TestContext context) throws IOException, URISyntaxException { - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED); - mockGet(new RegexPattern(RMAPI_POST_HOLDINGS_URL), RMAPI_RESPONSE_HOLDINGS); - - List<HoldingsMessage> messages = new ArrayList<>(); - Async async = context.async(EXPECTED_LOADED_PAGES); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, - message -> { - messages.add(((JsonObject) message.body()).getJsonObject("holdings").mapTo(HoldingsMessage.class)); - async.countDown(); - }); - vertx.eventBus().addOutboundInterceptor(interceptor); - - LoadServiceFacade proxy = LoadServiceFacade.createProxy(vertx, LOAD_FACADE_ADDRESS); - proxy.loadHoldings( - new LoadHoldingsMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT, 5001, 2, null, null)); - - async.await(TIMEOUT); - assertEquals(2, messages.size()); - assertEquals(STUB_HOLDINGS_TITLE, messages.getFirst().getHoldingList().getFirst().getPublicationTitle()); - } - - @Test - public void shouldRetryLoadingPageWhenPageFails(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), - "responses/rmapi/holdings/status/get-status-completed-one-page.json"); - - mockPostHoldings(); - mockResponseList(new UrlPathPattern(new EqualToPattern(RMAPI_POST_HOLDINGS_URL), false), - new ResponseDefinitionBuilder().withStatus(SC_INTERNAL_SERVER_ERROR), - new ResponseDefinitionBuilder() - .withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) - ); - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - @SuppressWarnings("checkstyle:methodLength") - public void shouldRetryCreationOfSnapshotAndUpdateHoldingsStatusWhenItFails(TestContext context) - throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - var failResponse = new ResponseDefinitionBuilder().withStatus(500); - var successResponse = new ResponseDefinitionBuilder() - .withBody(readFile(RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED_ONE_PAGE)); - mockResponseList(urlPathEqualTo(RMAPI_HOLDINGS_STATUS_URL), failResponse, successResponse, successResponse); - mockPostHoldings(); - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - mockGet(new RegexPattern(RMAPI_POST_HOLDINGS_URL), RMAPI_RESPONSE_HOLDINGS); - - async.await(TIMEOUT); - - assertTrue(async.isSucceeded()); - List<LoadStatusAttributes> attributes = HoldingsStatusAuditTestUtil.getRecords(vertx) - .stream().map(status -> status.getData().getAttributes()).toList(); - assertThat(attributes, containsInAnyOrder( - statusEquals(LoadStatusNameEnum.NOT_STARTED), - statusEquals(LoadStatusNameEnum.NOT_STARTED), - statusEquals(LoadStatusNameEnum.FAILED), - statusEquals(LoadStatusNameEnum.FAILED), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.POPULATING_STAGING_AREA, null), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 0), - statusEquals(LoadStatusNameEnum.IN_PROGRESS, LoadStatusNameDetailEnum.LOADING_HOLDINGS, 1), - statusEquals(LoadStatusNameEnum.COMPLETED) - )); - - HoldingsLoadingStatus holdingsLoadingStatus = HoldingsStatusUtil.getStatus(STUB_CREDENTIALS_ID, vertx); - assertThat(holdingsLoadingStatus.getData().getAttributes(), statusEquals(LoadStatusNameEnum.COMPLETED)); - } - - static void handleStatusChange(LoadStatusNameEnum status, HoldingsStatusRepositoryImpl repositorySpy, - Consumer<Void> handler) { - doAnswer(invocationOnMock -> { - @SuppressWarnings("unchecked") - CompletableFuture<Void> future = (CompletableFuture<Void>) invocationOnMock.callRealMethod(); - return future.thenAccept(handler); - }).when(repositorySpy).update( - argThat(argument -> argument.getData().getAttributes().getStatus().getName() == status), any(UUID.class), - anyString()); - } - - private void setupDefaultLoadKbConfiguration() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); - insertRetryStatus(STUB_CREDENTIALS_ID, vertx); - } - - private void runPostHoldingsWithMocks(TestContext context) throws IOException, URISyntaxException { - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), RMAPI_RESPONSE_HOLDINGS_STATUS_COMPLETED); - mockPostHoldings(); - mockGet(new RegexPattern(RMAPI_POST_HOLDINGS_URL), RMAPI_RESPONSE_HOLDINGS); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - } - - private void mockPostHoldings() { - StringValuePattern urlPattern = new EqualToPattern(RMAPI_POST_HOLDINGS_URL); - stubFor(post(new UrlPathPattern(urlPattern, false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody("") - .withStatus(202))); - } - - private Matcher<LoadStatusAttributes> statusEquals(LoadStatusNameEnum status) { - return statusEquals(status, null, null); - } - - private Matcher<LoadStatusAttributes> statusEquals(LoadStatusNameEnum status, LoadStatusNameDetailEnum detail, - Integer importedPages) { - return allOf( - hasProperty("status", hasProperty("name", equalTo(status))), - hasProperty("status", hasProperty("detail", equalTo(detail))), - hasProperty("importedPages", equalTo(importedPages)) - ); - } - - private void tearDownHoldingsData() { - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadServiceFacadeTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadServiceFacadeTest.java deleted file mode 100644 index fc4c44074..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadServiceFacadeTest.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.RmApiConstants.RMAPI_HOLDINGS_STATUS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_POST_HOLDINGS_URL; -import static org.folio.service.holdings.AbstractLoadServiceFacade.HOLDINGS_STATUS_TIME_FORMATTER; -import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGetWithBody; -import static org.folio.test.util.TestUtil.mockResponseList; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.test.util.TestUtil.readJsonFile; -import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; -import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.interceptAndStop; -import static org.junit.Assert.assertTrue; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.core.Handler; -import io.vertx.core.eventbus.DeliveryContext; -import io.vertx.core.json.Json; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.HoldingsLoadStatus; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.service.holdings.DefaultLoadServiceFacade; -import org.folio.service.holdings.message.ConfigurationMessage; -import org.folio.service.holdings.message.LoadHoldingsMessage; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class DefaultLoadServiceFacadeTest extends WireMockTestBase { - - private static final int TIMEOUT = 60000; - - @Autowired - private DefaultLoadServiceFacade loadServiceFacade; - private Configuration configuration; - private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - configuration = Configuration.builder() - .apiKey(STUB_API_KEY) - .customerId(STUB_CUSTOMER_ID) - .url(getWiremockUrl()) - .build(); - setupDefaultLoadKbConfiguration(); - } - - @After - public void tearDown() { - if (interceptor != null) { - vertx.eventBus().removeOutboundInterceptor(interceptor); - } - tearDownHoldingsData(); - } - - @Test - public void shouldCreateSnapshotOnInitialStatusNone(TestContext context) throws IOException, URISyntaxException { - Async async = context.async(); - - mockResponseList(new UrlPathPattern(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), false), - new ResponseDefinitionBuilder().withBody(readFile("responses/rmapi/holdings/status/get-status-none.json")), - new ResponseDefinitionBuilder().withBody(readFile("responses/rmapi/holdings/status/get-status-completed.json")) - ); - mockPostHoldings(); - - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, - message -> async.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - loadServiceFacade.createSnapshot(new ConfigurationMessage(configuration, STUB_CREDENTIALS_ID, STUB_TENANT)); - - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - public void shouldNotCreateSnapshotIfItWasRecentlyCreated(TestContext context) - throws IOException, URISyntaxException { - Async async = context.async(); - - String now = HOLDINGS_STATUS_TIME_FORMATTER.format(LocalDateTime.now(ZoneOffset.UTC)); - HoldingsLoadStatus status = - readJsonFile("responses/rmapi/holdings/status/get-status-completed.json", HoldingsLoadStatus.class) - .toBuilder().created(now).build(); - mockGetWithBody(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), Json.encode(status)); - mockPostHoldings(); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, - message -> async.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - loadServiceFacade.createSnapshot(new ConfigurationMessage(configuration, STUB_CREDENTIALS_ID, STUB_TENANT)); - - async.await(TIMEOUT); - - WireMock.verify(0, postRequestedFor(new UrlPathPattern(new EqualToPattern(RMAPI_POST_HOLDINGS_URL), false))); - } - - private void setupDefaultLoadKbConfiguration() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); - insertRetryStatus(STUB_CREDENTIALS_ID, vertx); - } - - private void mockPostHoldings() { - stubFor(post(new UrlPathPattern(new EqualToPattern(RMAPI_POST_HOLDINGS_URL), false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody("") - .withStatus(202))); - } - - private void tearDownHoldingsData() { - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAssignedUsersImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAssignedUsersImplTest.java deleted file mode 100644 index d5f715f43..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAssignedUsersImplTest.java +++ /dev/null @@ -1,280 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.AssignedUsersTestUtil.getAssignedUsers; -import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; -import static org.folio.util.KbCredentialsTestUtil.KB_CREDENTIALS_ENDPOINT; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.randomId; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertEquals; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; -import lombok.SneakyThrows; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.AssignedUser; -import org.folio.rest.jaxrs.model.AssignedUserCollection; -import org.folio.rest.jaxrs.model.AssignedUserId; -import org.folio.rest.jaxrs.model.AssignedUserPostRequest; -import org.folio.rest.jaxrs.model.Errors; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.test.util.TestUtil; -import org.folio.util.StringUtil; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) -public class EholdingsAssignedUsersImplTest extends WireMockTestBase { - - private static final String ASSIGN_USER_PATH = KB_CREDENTIALS_ENDPOINT + "/%s/users"; - private static final String KB_CREDENTIALS_ASSIGNED_USER_PATH = KB_CREDENTIALS_ENDPOINT + "/%s/users/%s"; - - private static final String USERDATA_COLLECTION_INFO_STUB_FILE = - "responses/userlookup/mock_user_collection_response_200.json"; - private static final String USERDATA_STUB_FILE = "responses/userlookup/mock_user_response_200.json"; - private static final String GROUP_INFO_STUB_FILE = "responses/userlookup/mock_group_collection_response_200.json"; - - private static final String QUERY_PARAM = "query"; - private static final String GET_USERS_ENDPOINT = "/users"; - - @After - public void tearDown() { - clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturn200WithCollection() throws IOException, URISyntaxException { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - saveAssignedUser(JOHN_ID, credentialsId, vertx); - saveAssignedUser(JANE_ID, credentialsId, vertx); - - List<UUID> ids = List.of(UUID.fromString(JOHN_ID), UUID.fromString(JANE_ID)); - - wireMockUsers(ids); - - final AssignedUserCollection assignedUsers = - getWithOk(String.format(ASSIGN_USER_PATH, credentialsId)).as(AssignedUserCollection.class); - assertEquals(2, (int) assignedUsers.getMeta().getTotalResults()); - assertEquals(2, assignedUsers.getData().size()); - } - - @Test - public void shouldReturn200WithEmptyCollection() { - String assignedUsersPath = String.format(ASSIGN_USER_PATH, randomId()); - - final AssignedUserCollection assignedUsers = getWithOk(assignedUsersPath).as(AssignedUserCollection.class); - assertEquals(0, (int) assignedUsers.getMeta().getTotalResults()); - assertEquals(0, assignedUsers.getData().size()); - } - - @Test - public void shouldReturn400WhenInvalidCredentialsId() { - String assignedUsersPath = String.format(ASSIGN_USER_PATH, "invalid-id"); - final JsonapiError error = getWithStatus(assignedUsersPath, SC_BAD_REQUEST).as(JsonapiError.class); - assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); - } - - @Test - @SneakyThrows - public void shouldReturn201OnPostWhenAssignedUserIsValid() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - AssignedUserId expected = stubAssignedUserId(credentialsId); - - AssignedUserPostRequest assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); - String postBody = Json.encode(assignedUserPostRequest); - String endpoint = String.format(ASSIGN_USER_PATH, credentialsId); - - wireMockUserById(expected.getId()); - - AssignedUserId actual = postWithCreated(endpoint, postBody).as(AssignedUserId.class); - - assertEquals(expected, actual); - - List<AssignedUser> assignedUsersInDb = getAssignedUsers(vertx); - assertThat(assignedUsersInDb, hasSize(1)); - assertEquals(expected.getId(), assignedUsersInDb.getFirst().getId()); - assertEquals(expected.getCredentialsId(), assignedUsersInDb.getFirst().getAttributes().getCredentialsId()); - } - - @Test - public void shouldReturn400OnPostWhenAssignedUserIsAlreadyAssigned() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - saveAssignedUser(JOHN_ID, credentialsId, vertx); - - AssignedUserPostRequest assignedUserPostRequest = new AssignedUserPostRequest() - .withData(stubAssignedUserId(credentialsId)); - - String postBody = Json.encode(assignedUserPostRequest); - String endpoint = String.format(ASSIGN_USER_PATH, credentialsId); - - wireMockUserById(JOHN_ID); - - JsonapiError error = postWithStatus(endpoint, postBody, SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "The user is already assigned"); - } - - @Test - public void shouldReturn404OnPostWhenAssignedUserToMissingCredentials() { - String credentialsId = randomId(); - AssignedUserId expected = stubAssignedUserId(credentialsId); - - AssignedUserPostRequest assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); - String postBody = Json.encode(assignedUserPostRequest); - String endpoint = String.format(ASSIGN_USER_PATH, credentialsId); - - wireMockUserById(expected.getId()); - - JsonapiError error = postWithStatus(endpoint, postBody, SC_NOT_FOUND).as(JsonapiError.class); - - assertErrorContainsTitle(error, "not found"); - } - - @Test - public void shouldReturn422OnPostWhenAssignedUserDoesNotHaveRequiredParameters() { - String credentialsId = randomId(); - AssignedUserId expected = new AssignedUserId(); - - AssignedUserPostRequest assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); - String postBody = Json.encode(assignedUserPostRequest); - String endpoint = String.format(ASSIGN_USER_PATH, credentialsId); - Errors errors = postWithStatus(endpoint, postBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); - - assertThat(errors.getErrors(), hasSize(1)); - assertThat(errors.getErrors(), everyItem(hasProperty("message", equalTo("must not be null")))); - } - - @Test - @SneakyThrows - public void shouldReturn422OnPostWhenUserDoesNotExist() { - String credentialsId = randomId(); - AssignedUserId expected = new AssignedUserId() - .withId(UUID.randomUUID().toString()) - .withCredentialsId(credentialsId); - - stubFor( - get(GET_USERS_ENDPOINT + "/" + expected.getId()) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(SC_NOT_FOUND))); - - AssignedUserPostRequest assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); - String postBody = Json.encode(assignedUserPostRequest); - String endpoint = String.format(ASSIGN_USER_PATH, credentialsId); - Errors errors = postWithStatus(endpoint, postBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); - - assertThat(errors.getErrors(), hasSize(1)); - assertThat(errors.getErrors(), everyItem(hasProperty("additionalProperties", - equalTo(Map.of("title", "Unable to assign user", "detail", "User doesn't exist"))))); - } - - @Test - public void shouldReturn204OnDeleteUserAssignment() throws IOException, URISyntaxException { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - String userId1 = saveAssignedUser(JOHN_ID, credentialsId, vertx); - String userId2 = saveAssignedUser(JANE_ID, credentialsId, vertx); - - List<UUID> ids = List.of(UUID.fromString(userId2)); - wireMockUsers(ids); - - deleteWithNoContent(String.format(KB_CREDENTIALS_ASSIGNED_USER_PATH, credentialsId, userId1)); - - final AssignedUserCollection assignedUsers = getWithOk(String.format(ASSIGN_USER_PATH, credentialsId)) - .as(AssignedUserCollection.class); - assertEquals(2, (int) assignedUsers.getMeta().getTotalResults()); - assertEquals(2, assignedUsers.getData().size()); - } - - @Test - public void shouldReturn400OnDeleteWhenInvalidUserId() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - final JsonapiError error = - deleteWithStatus(String.format(KB_CREDENTIALS_ASSIGNED_USER_PATH, credentialsId, "invalid-id"), SC_BAD_REQUEST) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); - } - - @Test - public void shouldReturn404OnDeleteWhenUserNotFound() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - final JsonapiError error = - deleteWithStatus(String.format(KB_CREDENTIALS_ASSIGNED_USER_PATH, credentialsId, randomId()), - SC_NOT_FOUND).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Assigned User not found by id"); - } - - private String cqlQueryConverter(List<UUID> ids) { - return "id=(" + ids.stream().map(UUID::toString) - .map(StringUtil::cqlEncode).collect(Collectors.joining(" OR ")) + ")"; - } - - private void wireMockUsers(List<UUID> ids) throws IOException, URISyntaxException { - String query = cqlQueryConverter(ids); - - stubFor( - get(new UrlPathPattern(new RegexPattern(GET_USERS_ENDPOINT), true)) - .withQueryParam(QUERY_PARAM, WireMock.equalTo(query)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(TestUtil.readFile(USERDATA_COLLECTION_INFO_STUB_FILE)))); - - UUID janeGroupId = UUID.fromString(JANE_GROUP_ID); - UUID johnGroupId = UUID.fromString(JOHN_GROUP_ID); - List<UUID> groupIds = List.of(johnGroupId, janeGroupId); - String cqlQuery = cqlQueryConverter(groupIds); - - stubFor( - get(new UrlPathPattern(new RegexPattern("/groups"), true)) - .withQueryParam(QUERY_PARAM, WireMock.equalTo(cqlQuery)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(TestUtil.readFile(GROUP_INFO_STUB_FILE)))); - } - - @SneakyThrows - private void wireMockUserById(String id) { - stubFor( - get(GET_USERS_ENDPOINT + "/" + id) - .willReturn(new ResponseDefinitionBuilder() - .withBody(TestUtil.readFile(USERDATA_STUB_FILE)))); - } - - private AssignedUserId stubAssignedUserId(String credentialsId) { - return new AssignedUserId() - .withId(WireMockTestBase.JOHN_ID) - .withCredentialsId(credentialsId); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCostperuseImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCostperuseImplTest.java deleted file mode 100644 index 086665888..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCostperuseImplTest.java +++ /dev/null @@ -1,806 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.holdings.HoldingsTableConstants.HOLDINGS_TABLE; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.repository.uc.UcCredentialsTableConstants.UC_CREDENTIALS_TABLE_NAME; -import static org.folio.repository.uc.UcSettingsTableConstants.UC_SETTINGS_TABLE_NAME; -import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.HoldingsTestUtil.saveHolding; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.UcCredentialsTestUtil.setUpUcCredentials; -import static org.folio.util.UcSettingsTestUtil.saveUcSettings; -import static org.folio.util.UcSettingsTestUtil.stubSettings; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertEquals; - -import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.OffsetDateTime; -import org.folio.client.uc.UcApigeeEbscoClient; -import org.folio.client.uc.UcAuthEbscoClient; -import org.folio.client.uc.model.UcAuthToken; -import org.folio.repository.holdings.DbHoldingInfo; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.PackageCostPerUse; -import org.folio.rest.jaxrs.model.ResourceCostPerUse; -import org.folio.rest.jaxrs.model.ResourceCostPerUseCollection; -import org.folio.rest.jaxrs.model.TitleCostPerUse; -import org.folio.test.util.TestUtil; -import org.jeasy.random.EasyRandom; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.util.ReflectionTestUtils; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class EholdingsCostperuseImplTest extends WireMockTestBase { - - private final EasyRandom random = new EasyRandom(); - - @Autowired - private UcAuthEbscoClient authEbscoClient; - @Autowired - private UcApigeeEbscoClient apigeeEbscoClient; - - private String credentialsId; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - credentialsId = saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - saveUcSettings(stubSettings(credentialsId), vertx); - setUpUcCredentials(vertx); - - ReflectionTestUtils.setField(authEbscoClient, "baseUrl", getWiremockUrl()); - ReflectionTestUtils.setField(apigeeEbscoClient, "baseUrl", getWiremockUrl()); - mockAuthToken(); - } - - @After - public void after() { - clearDataFromTable(vertx, UC_CREDENTIALS_TABLE_NAME); - clearDataFromTable(vertx, UC_SETTINGS_TABLE_NAME); - clearDataFromTable(vertx, HOLDINGS_TABLE); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnResourceCostPerUse() { - int titleId = 356; - int packageId = 473; - String year = "2019"; - String platform = "all"; - String stubApigeeResponseFile = "responses/uc/titles/get-title-cost-per-use-response.json"; - mockSuccessfulTitleCostPerUse(titleId, packageId, stubApigeeResponseFile); - - String kbEbscoResponseFile = "responses/kb-ebsco/costperuse/resources/expected-resource-cost-per-use.json"; - ResourceCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), ResourceCostPerUse.class); - - ResourceCostPerUse actual = getWithOk(resourceEndpoint(titleId, packageId, year, platform), JOHN_USER_ID_HEADER) - .as(ResourceCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturnEmptyResourceCostPerUse() { - int titleId = 356; - int packageId = 473; - String year = "2019"; - String stubApigeeResponseFile = "responses/uc/titles/get-empty-title-cost-per-use-response.json"; - mockSuccessfulTitleCostPerUse(titleId, packageId, stubApigeeResponseFile); - - String kbEbscoResponseFile = "responses/kb-ebsco/costperuse/resources/expected-empty-resource-cost-per-use.json"; - ResourceCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), ResourceCostPerUse.class); - - ResourceCostPerUse actual = getWithOk(resourceEndpoint(titleId, packageId, year, null), JOHN_USER_ID_HEADER) - .as(ResourceCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturnResourceCostPerUseWithEmptyNonPublisher() { - int titleId = 356; - int packageId = 473; - String year = "2019"; - String platform = "all"; - String stubApigeeResponseFile = "responses/uc/titles/get-title-cost-per-use-response-with-empty-non-publisher.json"; - mockSuccessfulTitleCostPerUse(titleId, packageId, stubApigeeResponseFile); - - String kbEbscoResponseFile = - "responses/kb-ebsco/costperuse/resources/expected-resource-cost-per-use-with-empty-non-publisher.json"; - ResourceCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), ResourceCostPerUse.class); - - ResourceCostPerUse actual = getWithOk(resourceEndpoint(titleId, packageId, year, platform), JOHN_USER_ID_HEADER) - .as(ResourceCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturn422OnGetResourceCpuWhenYearIsNull() { - int titleId = 356; - int packageId = 473; - JsonapiError error = getWithStatus(resourceEndpoint(titleId, packageId, null, null), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid fiscalYear"); - } - - @Test - public void shouldReturn422OnGetResourceCpuWhenPlatformIsInvalid() { - int titleId = 356; - int packageId = 473; - String year = "2019"; - String platform = "invalid"; - JsonapiError error = getWithStatus(resourceEndpoint(titleId, packageId, year, platform), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid platform"); - } - - @Test - public void shouldReturn400OnGetResourceCpuWhenApigeeFails() { - int titleId = 356; - int packageId = 473; - String year = "2019"; - - stubFor(get(urlPathMatching(String.format("/uc/costperuse/title/%s/%s", titleId, packageId))) - .willReturn(aResponse().withStatus(SC_BAD_REQUEST).withBody("Random error message")) - ); - - JsonapiError error = - getWithStatus(resourceEndpoint(titleId, packageId, year, null), SC_BAD_REQUEST, JOHN_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsDetail(error, "Random error message"); - } - - @Test - public void shouldReturnTitleCostPerUse() { - int titleId = 1111111111; - int packageId = 222222; - final String year = "2019"; - final String platform = "all"; - final String stubRmapiResponseFile = "responses/rmapi/titles/get-custom-title-with-coverage-dates-asc.json"; - - mockRmApiGetTitle(titleId, stubRmapiResponseFile); - String stubApigeeGetTitleResponseFile = "responses/uc/titles/get-title-cost-per-use-response.json"; - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-title-packages-cost-per-use-response.json"; - mockSuccessfulTitleCostPerUse(titleId, packageId, stubApigeeGetTitleResponseFile); - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - String kbEbscoResponseFile = "responses/kb-ebsco/costperuse/titles/expected-title-cost-per-use.json"; - TitleCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), TitleCostPerUse.class); - - TitleCostPerUse actual = getWithOk(titleEndpoint(titleId, year, platform), JOHN_USER_ID_HEADER) - .as(TitleCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturnTitleCostPerUseWithManagedEmbargoPeriod() { - int titleId = 1111111111; - int packageId = 222222; - final String year = "2019"; - final String platform = "nonPublisher"; - final String stubRmapiResponseFile = "responses/rmapi/titles/get-custom-title-with-managed-embargo.json"; - - mockRmApiGetTitle(titleId, stubRmapiResponseFile); - String stubApigeeGetTitleResponseFile = "responses/uc/titles/get-empty-title-cost-per-use-response.json"; - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-title-packages-cost-per-use-response.json"; - mockSuccessfulTitleCostPerUse(titleId, packageId, stubApigeeGetTitleResponseFile); - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - String kbEbscoResponseFile = "responses/kb-ebsco/costperuse/titles/expected-title-cost-per-use-with-no-usage.json"; - TitleCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), TitleCostPerUse.class); - - TitleCostPerUse actual = getWithOk(titleEndpoint(titleId, year, platform), JOHN_USER_ID_HEADER) - .as(TitleCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturnEmptyTitleCostPerUseWhenNoCostPerUseDataAvailable() { - int titleId = 1111111111; - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final String stubRmapiResponseFile = "responses/rmapi/titles/get-custom-title-with-coverage-dates-asc.json"; - - mockRmApiGetTitle(titleId, stubRmapiResponseFile); - String stubApigeeGetTitleResponseFile = "responses/uc/titles/get-empty-title-cost-per-use-response.json"; - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-title-packages-cost-per-use-response.json"; - mockSuccessfulTitleCostPerUse(titleId, packageId, stubApigeeGetTitleResponseFile); - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - String kbEbscoResponseFile = "responses/kb-ebsco/costperuse/titles/expected-title-cost-per-use-with-no-usage.json"; - TitleCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), TitleCostPerUse.class); - - TitleCostPerUse actual = getWithOk(titleEndpoint(titleId, year, platform), JOHN_USER_ID_HEADER) - .as(TitleCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturnEmptyTitleCostPerUseWhenNoSelectedResources() { - int titleId = 1111111111; - String year = "2019"; - String platform = "all"; - - String stubRmapiResponseFile = "responses/rmapi/titles/get-custom-title-with-no-selected-resources.json"; - mockRmApiGetTitle(titleId, stubRmapiResponseFile); - - String kbEbscoResponseFile = "responses/kb-ebsco/costperuse/titles/expected-empty-title-cost-per-use.json"; - TitleCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), TitleCostPerUse.class); - - TitleCostPerUse actual = getWithOk(titleEndpoint(titleId, year, platform), JOHN_USER_ID_HEADER) - .as(TitleCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturn422OnGetTitleCpuWhenYearIsNull() { - int titleId = 356; - JsonapiError error = getWithStatus(titleEndpoint(titleId, null, null), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid fiscalYear"); - } - - @Test - public void shouldReturn422OnGetTitleCpuWhenPlatformIsInvalid() { - int titleId = 356; - String year = "2019"; - String platform = "invalid"; - JsonapiError error = getWithStatus(titleEndpoint(titleId, year, platform), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid platform"); - } - - @Test - public void shouldReturnPackageCostPerUse() { - int packageId = 222222; - String year = "2019"; - String platform = "all"; - - String stubApigeeGetPackageResponseFile = "responses/uc/packages/get-package-cost-per-use-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - - String kbEbscoResponseFile = "responses/kb-ebsco/costperuse/packages/expected-package-cost-per-use.json"; - PackageCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), PackageCostPerUse.class); - - PackageCostPerUse actual = getWithOk(packageEndpoint(packageId, year, platform), JOHN_USER_ID_HEADER) - .as(PackageCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturnPackageCostPerUseWhenPackageCostIsEmpty() { - int packageId = 222222; - final String year = "2019"; - final String platform = "all"; - - var holding1 = new DbHoldingInfo(1, packageId, 1, "Ionicis tormentos accelerare!", "Sunt hydraes", "Book"); - var holding2 = new DbHoldingInfo(2, packageId, 1, "Vortex, plasmator, et lixa.", "Est germanus byssus", "Book"); - saveHolding(credentialsId, holding1, OffsetDateTime.now(), vertx); - saveHolding(credentialsId, holding2, OffsetDateTime.now(), vertx); - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - String kbEbscoResponseFile = - "responses/kb-ebsco/costperuse/packages/expected-package-cost-per-use-when-cost-is-empty.json"; - PackageCostPerUse expected = Json.decodeValue(readFile(kbEbscoResponseFile), PackageCostPerUse.class); - - PackageCostPerUse actual = getWithOk(packageEndpoint(packageId, year, platform), JOHN_USER_ID_HEADER) - .as(PackageCostPerUse.class); - - assertEquals(expected, actual); - } - - @Test - public void shouldReturn422OnGetPackageCpuWhenYearIsNull() { - int packageId = 222222; - JsonapiError error = getWithStatus(packageEndpoint(packageId, null, null), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid fiscalYear"); - } - - @Test - public void shouldReturn422OnGetPackageCpuWhenPlatformIsInvalid() { - int packageId = 222222; - String year = "2019"; - String platform = "invalid"; - JsonapiError error = getWithStatus(packageEndpoint(packageId, year, platform), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid platform"); - } - - @Test - public void shouldReturn400OnGetPackageCpuWhenApigeeFails() { - int packageId = 222222; - String year = "2019"; - - stubFor(get(urlPathMatching(String.format("/uc/costperuse/package/%s", packageId))) - .willReturn(aResponse().withStatus(SC_BAD_REQUEST).withBody("Random error message")) - ); - - JsonapiError error = getWithStatus(packageEndpoint(packageId, year, null), SC_BAD_REQUEST, JOHN_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsDetail(error, "Random error message"); - } - - @Test - public void shouldReturnResourcesCostPerUseCollection() { - int packageId = 222222; - final String year = "2019"; - final String platform = "all"; - - for (int i = 1; i <= 20; i++) { - saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-multiply-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - ResourceCostPerUseCollection - actual = getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null), JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(20)); - assertThat(actual.getData(), hasSize(20)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().getFirst().getAttributes(), hasProperty("usage", equalTo(2))); - assertThat(actual.getData().getFirst().getAttributes(), hasProperty("percent", equalTo(2.0 / 36 * 100))); - } - - @Test - public void shouldReturnResourcesCostPerUseCollectionWithPagination() { - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final var page = "2"; - final var size = "15"; - - for (int i = 1; i <= 20; i++) { - saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-multiply-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - ResourceCostPerUseCollection actual = - getWithOk(packageResourcesEndpoint(packageId, year, platform, page, size), JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(20)); - assertThat(actual.getData(), hasSize(5)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().getFirst().getAttributes(), hasProperty("usage", equalTo(1))); - } - - @Test - public void shouldReturnResourcesCostPerUseCollectionWithSortByUsageAsc() { - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final String sort = "usage"; - final String order = "asc"; - - for (int i = 1; i <= 3; i++) { - saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-different-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - var actual = - getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, order), JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(3)); - assertThat(actual.getData(), hasSize(3)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().get(0).getAttributes(), hasProperty("usage", equalTo(1))); - assertThat(actual.getData().get(2).getAttributes(), hasProperty("usage", equalTo(10))); - } - - @Test - public void shouldReturnResourcesCostPerUseCollectionWithSortByUsageDesc() { - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final String sort = "usage"; - final String order = "desc"; - - for (int i = 1; i <= 3; i++) { - saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-different-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - var actual = - getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, order), JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(3)); - assertThat(actual.getData(), hasSize(3)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().get(0).getAttributes(), hasProperty("usage", equalTo(10))); - assertThat(actual.getData().get(2).getAttributes(), hasProperty("usage", equalTo(1))); - } - - @Test - public void shouldReturnResourcesCostPerUseCollectionWithSortByCost() { - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final String sort = "cost"; - - for (int i = 1; i <= 3; i++) { - saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-different-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - ResourceCostPerUseCollection - actual = getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null), - JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(3)); - assertThat(actual.getData(), hasSize(3)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().get(0).getAttributes(), hasProperty("cost", nullValue())); - assertThat(actual.getData().get(2).getAttributes(), hasProperty("cost", equalTo(200.0))); - } - - @Test - public void shouldReturnResourcesCostPerUseCollectionWithSortByCostPerUse() { - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final String sort = "costperuse"; - - for (int i = 1; i <= 3; i++) { - saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-different-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - ResourceCostPerUseCollection - actual = getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null), - JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(3)); - assertThat(actual.getData(), hasSize(3)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().get(0).getAttributes(), hasProperty("costPerUse", nullValue())); - assertThat(actual.getData().get(2).getAttributes(), hasProperty("costPerUse", equalTo(50.0))); - } - - @Test - public void shouldReturnResourcesCostPerUseCollectionWithSortByPercent() { - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final String sort = "percent"; - - for (int i = 1; i <= 3; i++) { - saveHolding(credentialsId, generateHolding(packageId, i), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-different-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - ResourceCostPerUseCollection - actual = getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null), - JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(3)); - assertThat(actual.getData(), hasSize(3)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().get(0).getAttributes(), hasProperty("percent", equalTo(1.0 / 26 * 100))); - assertThat(actual.getData().get(2).getAttributes(), hasProperty("percent", equalTo(10.0 / 26 * 100))); - } - - @Test - public void shouldReturnResourcesCostPerUseCollectionSortedByNameWhenSortingByEqualsValues() { - int packageId = 222222; - final String year = "2019"; - final String platform = "publisher"; - final String sort = "type"; - - for (int i = 1; i <= 3; i++) { - saveHolding(credentialsId, generateHolding(packageId, i, String.valueOf(i)), OffsetDateTime.now(), vertx); - } - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - String stubApigeeGetTitlePackageResponseFile = - "responses/uc/title-packages/get-different-title-packages-cost-per-use-for-package-response.json"; - mockSuccessfulTitlePackageCostPerUse(stubApigeeGetTitlePackageResponseFile); - - ResourceCostPerUseCollection - actual = getWithOk(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null), - JOHN_USER_ID_HEADER) - .as(ResourceCostPerUseCollection.class); - - assertThat(actual, notNullValue()); - assertThat(actual.getMeta().getTotalResults(), equalTo(3)); - assertThat(actual.getData(), hasSize(3)); - assertThat(actual.getData(), everyItem(hasProperty("resourceId", startsWith("1-" + packageId)))); - assertThat(actual.getData().get(0).getAttributes(), hasProperty("name", equalTo("1"))); - assertThat(actual.getData().get(2).getAttributes(), hasProperty("name", equalTo("3"))); - } - - @Test - public void shouldReturn422OnGetPackageResourcesCpuWhenYearIsNull() { - int packageId = 222222; - JsonapiError error = - getWithStatus(packageResourcesEndpoint(packageId, null, null, null, null), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid fiscalYear"); - } - - @Test - public void shouldReturn422OnGetPackageResourcesCpuWhenPlatformIsInvalid() { - int packageId = 222222; - String year = "2019"; - String platform = "invalid"; - JsonapiError error = - getWithStatus(packageResourcesEndpoint(packageId, year, platform, null, null), SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid platform"); - } - - @Test - public void shouldReturn422OnGetPackageResourcesCpuWhenSortIsInvalid() { - int packageId = 222222; - String year = "2019"; - String platform = "all"; - String sort = "invalid"; - JsonapiError error = - getWithStatus(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null), - SC_UNPROCESSABLE_ENTITY) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid sort"); - } - - @Test - public void shouldReturn400OnGetPackageResourcesCpuWhenApigeeFails() { - final int packageId = 222222; - final String year = "2019"; - - saveHolding(credentialsId, generateHolding(packageId, 1), OffsetDateTime.now(), vertx); - - String stubApigeeGetPackageResponseFile = - "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - mockSuccessfulPackageCostPerUse(packageId, stubApigeeGetPackageResponseFile); - - stubFor(post(urlPathMatching("/uc/costperuse/titles")) - .willReturn(aResponse().withStatus(SC_BAD_REQUEST).withBody("Random error message")) - ); - - JsonapiError error = - getWithStatus(packageResourcesEndpoint(packageId, year, null, null, null), SC_BAD_REQUEST, JOHN_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsDetail(error, "Random error message"); - } - - private void mockRmApiGetTitle(int titleId, String stubRmapiResponseFile) { - stubFor(get(urlPathMatching("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + titleId)) - .willReturn(aResponse().withBody(readFile(stubRmapiResponseFile))) - ); - } - - private void mockSuccessfulTitleCostPerUse(int titleId, int packageId, String filePath) { - stubFor(get(urlPathMatching(String.format("/uc/costperuse/title/%s/%s", titleId, packageId))) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(filePath))) - ); - } - - private void mockSuccessfulPackageCostPerUse(int packageId, String filePath) { - stubFor(get(urlPathMatching(String.format("/uc/costperuse/package/%s", packageId))) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(filePath))) - ); - } - - private void mockSuccessfulTitlePackageCostPerUse(String filePath) { - stubFor(post(urlPathMatching("/uc/costperuse/titles")) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(filePath))) - ); - } - - private void mockAuthToken() { - UcAuthToken stubToken = new UcAuthToken("access_token", "Bearer", 3600L, "openid"); - stubFor(post(urlPathMatching("/oauth-proxy/token")) - .willReturn(aResponse().withStatus(SC_OK).withBody(Json.encode(stubToken))) - ); - } - - private String readFile(String filePath) { - try { - return TestUtil.readFile(filePath); - } catch (IOException | URISyntaxException e) { - Assert.fail(e.getMessage()); - return null; - } - } - - private String resourceEndpoint(int titleId, int packageId, String year, String platform) { - String baseUrl = String.format("eholdings/resources/1-%s-%s/costperuse", packageId, titleId); - StringBuilder paramsSb = getEndpointParams(year, platform); - return !paramsSb.isEmpty() - ? baseUrl + "?" + paramsSb - : baseUrl; - } - - private String titleEndpoint(int titleId, String year, String platform) { - String baseUrl = String.format("eholdings/titles/%s/costperuse", titleId); - StringBuilder paramsSb = getEndpointParams(year, platform); - return !paramsSb.isEmpty() - ? baseUrl + "?" + paramsSb - : baseUrl; - } - - private String packageEndpoint(int packageId, String year, String platform) { - String baseUrl = String.format("eholdings/packages/1-%s/costperuse", packageId); - StringBuilder paramsSb = getEndpointParams(year, platform); - return !paramsSb.isEmpty() - ? baseUrl + "?" + paramsSb - : baseUrl; - } - - private String packageResourcesEndpoint(int packageId, String year, String platform, String page, String size) { - return packageResourcesEndpoint(packageId, year, platform, page, size, null, null); - } - - private String packageResourcesEndpoint(int packageId, String year, String platform, String page, String size, - String sort, String order) { - String baseUrl = String.format("eholdings/packages/1-%s/resources/costperuse", packageId); - StringBuilder paramsSb = getEndpointParams(year, platform, page, size, sort, order); - return !paramsSb.isEmpty() - ? baseUrl + "?" + paramsSb - : baseUrl; - } - - private StringBuilder getEndpointParams(String year, String platform) { - return getEndpointParams(year, platform, null, null, null, null); - } - - private StringBuilder getEndpointParams(String year, String platform, String page, String size, String sort, - String order) { - StringBuilder paramsSb = new StringBuilder(); - if (year != null) { - paramsSb.append("fiscalYear=").append(year); - } - addParam(platform, paramsSb, "platform="); - addParam(page, paramsSb, "page="); - addParam(size, paramsSb, "count="); - addParam(sort, paramsSb, "sort="); - addParam(order, paramsSb, "order="); - return paramsSb; - } - - private void addParam(String platform, StringBuilder paramsSb, String s) { - if (platform != null) { - if (!paramsSb.isEmpty()) { - paramsSb.append("&"); - } - paramsSb.append(s).append(platform); - } - } - - private DbHoldingInfo generateHolding(int packageId, int titleId) { - return DbHoldingInfo.builder() - .packageId(packageId) - .titleId(titleId) - .publicationTitle(random.nextObject(String.class)) - .publisherName(random.nextObject(String.class)) - .resourceType("Book") - .vendorId(1) - .build(); - } - - private DbHoldingInfo generateHolding(int packageId, int titleId, String titleName) { - return DbHoldingInfo.builder() - .packageId(packageId) - .titleId(titleId) - .publicationTitle(titleName) - .publisherName(random.nextObject(String.class)) - .resourceType("Book") - .vendorId(1) - .build(); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCurrenciesImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCurrenciesImplTest.java deleted file mode 100644 index f6a0164b7..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCurrenciesImplTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static org.apache.http.HttpStatus.SC_OK; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.notNullValue; - -import io.vertx.ext.unit.junit.VertxUnitRunner; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.Currency; -import org.folio.rest.jaxrs.model.CurrencyCollection; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) -public class EholdingsCurrenciesImplTest extends WireMockTestBase { - - public static final String CURRENCIES_ENDPOINT = "/eholdings/currencies"; - - @Test - public void shouldReturnAccessTypeCollectionOnGet() { - CurrencyCollection actual = getWithStatus(CURRENCIES_ENDPOINT, SC_OK).as(CurrencyCollection.class); - getWithStatus(CURRENCIES_ENDPOINT, SC_OK).as(CurrencyCollection.class); - - assertThat(actual.getMeta().getTotalResults(), greaterThan(0)); - assertThat(actual.getData(), hasSize(actual.getMeta().getTotalResults())); - assertThat(actual.getData().getFirst(), notNullValue()); - assertThat(actual.getData().getFirst(), - allOf( - hasProperty("id", equalTo("AFN")), - hasProperty("type", equalTo(Currency.Type.CURRENCIES)) - ) - ); - assertThat(actual.getData().getFirst().getAttributes(), - allOf( - hasProperty("code", equalTo("AFN")), - hasProperty("description", equalTo("Afghan Afghani")) - ) - ); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCustomLabelsImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCustomLabelsImplTest.java deleted file mode 100644 index e27de0969..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCustomLabelsImplTest.java +++ /dev/null @@ -1,210 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.apache.http.HttpStatus.SC_FORBIDDEN; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.test.util.TestUtil.readJsonFile; -import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbCredentialsTestUtil.KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.getDefaultKbConfiguration; -import static org.folio.util.KbTestUtil.setupDefaultKbConfiguration; -import static org.junit.Assert.assertEquals; - -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.UUID; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.CustomLabelsCollection; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.KbCredentials; -import org.json.JSONException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.skyscreamer.jsonassert.JSONAssert; - -@RunWith(VertxUnitRunner.class) -public class EholdingsCustomLabelsImplTest extends WireMockTestBase { - - private static final String KB_CUSTOM_LABELS_PATH = "eholdings/custom-labels"; - private static final String RM_API_CUSTOMER_PATH = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/"; - - private static final String REQUESTS_PATH = "requests/kb-ebsco/custom-labels"; - private static final String PUT_ONE_LABEL_REQUEST = REQUESTS_PATH + "/put-one-custom-label.json"; - private static final String PUT_FIVE_LABEL_REQUEST = REQUESTS_PATH + "/put-five-custom-labels.json"; - private static final String PUT_WITH_INVALID_ID_REQUEST = REQUESTS_PATH + "/put-custom-label-invalid-id.json"; - private static final String PUT_WITH_INVALID_NAME_REQUEST = REQUESTS_PATH + "/put-custom-label-invalid-name.json"; - private static final String PUT_WITH_DUPLICATE_ID_REQUEST = REQUESTS_PATH + "/put-custom-labels-duplicate-id.json"; - - private static final String KB_GET_CUSTOM_LABELS_RESPONSE = - "responses/kb-ebsco/custom-labels/get-custom-labels-list.json"; - - private static final String RM_GET_LABELS_RESPONSE = "responses/rmapi/proxiescustomlabels/get-success-response.json"; - private static final String RM_PUT_ONE_LABEL_REQUEST = "requests/rmapi/proxiescustomlabels/put-one-label.json"; - private static final String RM_PUT_FIVE_LABEL_REQUEST = "requests/rmapi/proxiescustomlabels/put-five-labels.json"; - - private KbCredentials configuration; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - configuration = getDefaultKbConfiguration(vertx); - } - - @After - public void tearDown() { - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnCustomLabelsOnGet() throws IOException, URISyntaxException, JSONException { - mockCustomLabelsConfiguration(); - - String actual = getWithOk(KB_CUSTOM_LABELS_PATH, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals(readFile(KB_GET_CUSTOM_LABELS_RESPONSE), actual, false); - verify(1, getRequestedFor(urlEqualTo(RM_API_CUSTOMER_PATH))); - } - - @Test - public void shouldReturn403OnGetWithResourcesWhenRmApi401() { - mockGet(new RegexPattern(RM_API_CUSTOMER_PATH), SC_UNAUTHORIZED); - - JsonapiError error = getWithStatus(KB_CUSTOM_LABELS_PATH, SC_FORBIDDEN, STUB_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturn403OnGetWithResourcesWhenRmApi403() { - mockGet(new RegexPattern(RM_API_CUSTOMER_PATH), SC_FORBIDDEN); - - JsonapiError error = getWithStatus(KB_CUSTOM_LABELS_PATH, SC_FORBIDDEN, STUB_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturnCustomLabelsOnGetByCredentials() throws IOException, URISyntaxException { - CustomLabelsCollection expected = readJsonFile(KB_GET_CUSTOM_LABELS_RESPONSE, CustomLabelsCollection.class); - expected.getData().forEach(customLabel -> customLabel.setCredentialsId(configuration.getId())); - - mockCustomLabelsConfiguration(); - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, configuration.getId()); - CustomLabelsCollection actual = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(CustomLabelsCollection.class); - - verify(1, getRequestedFor(urlEqualTo(RM_API_CUSTOMER_PATH))); - assertEquals(expected, actual); - } - - @Test - public void shouldReturn403OnGetByCredentialsWithResourcesWhenRmApi403() { - mockGet(new RegexPattern(RM_API_CUSTOMER_PATH), SC_FORBIDDEN); - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, configuration.getId()); - JsonapiError error = getWithStatus(resourcePath, SC_FORBIDDEN, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturn404OnGetByCredentialsWhenCredentialsAreMissing() { - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); - JsonapiError error = getWithStatus(resourcePath, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "KbCredentials not found by id"); - } - - @Test - public void shouldUpdateCustomLabelsOnPutWhenAllIsValidWithOneItem() - throws IOException, URISyntaxException, JSONException { - mockCustomLabelsSuccessPutRequest(); - - String putBody = readFile(PUT_ONE_LABEL_REQUEST); - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, configuration.getId()); - String actual = putWithOk(resourcePath, putBody, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(PUT_ONE_LABEL_REQUEST), actual, false); - - verify(1, putRequestedFor(urlEqualTo(RM_API_CUSTOMER_PATH)) - .withRequestBody(equalToJson(readFile(RM_PUT_ONE_LABEL_REQUEST)))); - } - - @Test - public void shouldUpdateCustomLabelsOnPutWhenAllIsValidWithFiveItems() - throws IOException, URISyntaxException, JSONException { - mockCustomLabelsSuccessPutRequest(); - - String putBody = readFile(PUT_FIVE_LABEL_REQUEST); - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, configuration.getId()); - String actual = putWithOk(resourcePath, putBody, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(PUT_FIVE_LABEL_REQUEST), actual, false); - - verify(1, putRequestedFor(urlEqualTo(RM_API_CUSTOMER_PATH)) - .withRequestBody(equalToJson(readFile(RM_PUT_FIVE_LABEL_REQUEST)))); - } - - @Test - public void shouldReturn422OnPutWhenIdNotInRange() throws IOException, URISyntaxException { - String putBody = readFile(PUT_WITH_INVALID_ID_REQUEST); - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid Custom Label id"); - assertErrorContainsDetail(error, "Custom Label id should be in range 1 - 5"); - } - - @Test - public void shouldReturn422OnPutWhenInvalidNameLength() throws IOException, URISyntaxException { - String putBody = readFile(PUT_WITH_INVALID_NAME_REQUEST); - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid Custom Label Name"); - assertErrorContainsDetail(error, "Custom Label Name is too long (maximum is 50 characters)"); - } - - @Test - public void shouldReturn422OnPutWhenHasDuplicateIds() throws IOException, URISyntaxException { - String putBody = readFile(PUT_WITH_DUPLICATE_ID_REQUEST); - String resourcePath = String.format(KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT, UUID.randomUUID()); - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid request body"); - assertErrorContainsDetail(error, "Each label in body must contain unique id"); - } - - private void mockCustomLabelsConfiguration() throws IOException, URISyntaxException { - stubFor(get(urlEqualTo(RM_API_CUSTOMER_PATH)) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(RM_GET_LABELS_RESPONSE)))); - } - - private void mockCustomLabelsSuccessPutRequest() throws IOException, URISyntaxException { - mockCustomLabelsConfiguration(); - stubFor(put(urlEqualTo(RM_API_CUSTOMER_PATH)) - .willReturn(aResponse().withStatus(SC_NO_CONTENT))); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsExportImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsExportImplTest.java deleted file mode 100644 index 7015eec27..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsExportImplTest.java +++ /dev/null @@ -1,272 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.ok; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.repository.uc.UcSettingsTableConstants.UC_SETTINGS_TABLE_NAME; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.UcCredentialsTestUtil.setUpUcCredentials; -import static org.folio.util.UcSettingsTestUtil.saveUcSettings; -import static org.folio.util.UcSettingsTestUtil.stubSettings; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.notNullValue; - -import io.restassured.http.Header; -import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.OffsetDateTime; -import org.apache.http.protocol.HTTP; -import org.folio.client.uc.UcApigeeEbscoClient; -import org.folio.client.uc.UcAuthEbscoClient; -import org.folio.client.uc.model.UcAuthToken; -import org.folio.repository.holdings.DbHoldingInfo; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.util.HoldingsTestUtil; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.util.ReflectionTestUtils; - -@RunWith(VertxUnitRunner.class) -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -public class EholdingsExportImplTest extends WireMockTestBase { - - public static final String UC_COSTPERUSE_PACKAGE_REQ = "/uc/costperuse/package/%s"; - public static final String UC_COSTPERUSE_TITLES_REQ = "/uc/costperuse/titles"; - protected static final Header CONTENT_TYPE_CSV_HEADER = new Header(HTTP.CONTENT_TYPE, "text/csv"); - private static final String EXPORT_PACKAGE_TITLES = "/eholdings/packages/%d-%d/resources/costperuse/export%s"; - private static final int STUB_PROVIDER_ID = 123; - private static final int STUB_PACKAGE_ID = 456; - private static final String STUB_QUERY_PARAMS = "?platform=publisher&fiscalYear=2019"; - private String credentialsId; - - @Autowired - private UcAuthEbscoClient authEbscoClient; - @Autowired - private UcApigeeEbscoClient apigeeEbscoClient; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - ReflectionTestUtils.setField(authEbscoClient, "baseUrl", getWiremockUrl()); - ReflectionTestUtils.setField(apigeeEbscoClient, "baseUrl", getWiremockUrl()); - credentialsId = saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - } - - @After - public void tearDown() { - clearDataFromTable(vertx, UC_SETTINGS_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnExportResponse() throws IOException, URISyntaxException { - setUpUcCredentials(vertx); - saveUcSettings(stubSettings(credentialsId), vertx); - mockAuthToken(); - - saveHoldingFromFile("responses/kb-ebsco/export/holding-for-export-1.json", - "responses/kb-ebsco/export/holding-for-export-2.json", - "responses/kb-ebsco/export/holding-for-export-3.json"); - mockFailedLocaleResponse(); - - String apigeeGetPackageResponse = "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - stubFor(get(urlPathMatching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID))) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(apigeeGetPackageResponse))) - ); - - String apigeeGetTitlePackageResponse = - "responses/export/get-different-title-packages-response.json"; - stubFor(post(urlPathMatching(UC_COSTPERUSE_TITLES_REQ)) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(apigeeGetTitlePackageResponse))) - ); - - var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); - - String actual = getWithOk(url, JOHN_USER_ID_HEADER, CONTENT_TYPE_CSV_HEADER).body().asString(); - - assertThat(actual, notNullValue()); - assertThat(actual, Matchers.equalTo(readFile("responses/kb-ebsco/export/expected-export-three-items-usd.txt"))); - } - - @Test - public void shouldReturnExportWithZeroValuesResponseWhenNoCostPerUseInfo() throws IOException, URISyntaxException { - setUpUcCredentials(vertx); - saveUcSettings(stubSettings(credentialsId), vertx); - mockAuthToken(); - - saveHoldingFromFile("responses/kb-ebsco/export/holding-for-export-1.json", - "responses/kb-ebsco/export/holding-for-export-2.json", - "responses/kb-ebsco/export/holding-for-export-3.json"); - - mockSuccessfulLocaleResponse(); - - String apigeeGetPackageResponse = "responses/uc/packages/empty-package-cost-per-use-response.json"; - - stubFor(get(urlPathMatching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID))) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(apigeeGetPackageResponse))) - ); - - String apigeeGetTitlePackageResponse = "responses/export/get-empty-cost-per-use-title-response.json"; - stubFor(post(urlPathMatching(UC_COSTPERUSE_TITLES_REQ)) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(apigeeGetTitlePackageResponse))) - ); - - var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); - String actual = getWithOk(url, JOHN_USER_ID_HEADER, CONTENT_TYPE_CSV_HEADER).body().asString(); - assertThat(actual, notNullValue()); - - assertThat(actual, - Matchers.equalTo(readFile("responses/kb-ebsco/export/expected-export-three-items-zero-values.txt"))); - } - - @Test - public void shouldReturnEmptyResponseWhenNoHoldings() throws IOException, URISyntaxException { - setUpUcCredentials(vertx); - saveUcSettings(stubSettings(credentialsId), vertx); - mockAuthToken(); - - mockSuccessfulLocaleResponse(); - - String apigeeGetPackageResponse = "responses/uc/packages/empty-package-cost-per-use-response.json"; - - stubFor(get(urlPathMatching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID))) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(apigeeGetPackageResponse))) - ); - - var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); - String actual = getWithOk(url, JOHN_USER_ID_HEADER, CONTENT_TYPE_CSV_HEADER).body().asString(); - - String ucPackagePublisher = - "/uc/costperuse/package/456?fiscalYear=2019&fiscalMonth=apr&analysisCurrency=USD&aggregatedFullText=true"; - verify(1, getRequestedFor(urlEqualTo(ucPackagePublisher))); - - String ucTitles = "/uc/costperuse/titles?"; - verify(0, getRequestedFor(urlMatching(ucTitles))); - - assertThat(actual, Matchers.equalTo(readFile("responses/kb-ebsco/export/expected-empty-export-response.txt"))); - } - - @Test - public void shouldReturnResponseWithPublisherEqualsToAllWhenNotSpecifiedInUrl() - throws IOException, URISyntaxException { - setUpUcCredentials(vertx); - saveUcSettings(stubSettings(credentialsId), vertx); - mockAuthToken(); - - saveHoldingFromFile("responses/kb-ebsco/export/holding-for-export-1.json", - "responses/kb-ebsco/export/holding-for-export-2.json", - "responses/kb-ebsco/export/holding-for-export-3.json"); - - mockFailedLocaleResponse(); - - String apigeeGetPackageResponse = "responses/uc/packages/get-package-cost-per-use-with-empty-cost-response.json"; - stubFor(get(urlPathMatching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID))) - .willReturn(ok(readFile(apigeeGetPackageResponse)))); - - String apigeeGetTitlePackageResponse = "responses/export/get-different-title-packages-response.json"; - stubFor(post(urlPathMatching(UC_COSTPERUSE_TITLES_REQ)).willReturn(ok(readFile(apigeeGetTitlePackageResponse)))); - var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, "?fiscalYear=2019"); - - String actual = getWithOk(url, JOHN_USER_ID_HEADER, CONTENT_TYPE_CSV_HEADER).body().asString(); - assertThat(actual, notNullValue()); - - verify(1, getRequestedFor(urlEqualTo("/uc/costperuse/package/456?fiscalYear=?" - + "&fiscalMonth=apr&analysisCurrency=USD&aggregatedFullText=true"))); - verify(1, postRequestedFor(urlEqualTo(titlesUrl("2019", "apr", "USD", false, false)))); - verify(1, postRequestedFor(urlEqualTo(titlesUrl("2019", "apr", "USD", true, false)))); - } - - @Test - public void shouldReturn401ErrorWhenCanNotRetrieveAuthToken() { - setUpUcCredentials(vertx); - saveUcSettings(stubSettings(credentialsId), vertx); - - String errorMessage = "Unable to proceed request"; - stubFor(post(urlPathMatching("/oauth-proxy/token")) - .willReturn(aResponse().withStatus(SC_BAD_REQUEST).withBody(errorMessage)) - ); - mockSuccessfulLocaleResponse(); - - var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); - - getWithStatus(url, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER, CONTENT_TYPE_CSV_HEADER).as(JsonapiError.class); - } - - @Test - public void shouldReturnExportFileWithDefaultLocaleSettings() throws IOException, URISyntaxException { - - setUpUcCredentials(vertx); - saveUcSettings(stubSettings(credentialsId), vertx); - mockAuthToken(); - - saveHoldingFromFile("responses/kb-ebsco/export/holding-for-export-1.json", - "responses/kb-ebsco/export/holding-for-export-2.json", - "responses/kb-ebsco/export/holding-for-export-3.json"); - - mockFailedLocaleResponse(); - - String apigeeGetPackageResponse = "responses/uc/packages/empty-package-cost-per-use-response.json"; - - stubFor(get(urlPathMatching(String.format(UC_COSTPERUSE_PACKAGE_REQ, STUB_PACKAGE_ID))) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(apigeeGetPackageResponse))) - ); - - String apigeeGetTitlePackageResponse = "responses/export/get-empty-cost-per-use-title-response.json"; - stubFor(post(urlPathMatching(UC_COSTPERUSE_TITLES_REQ)) - .willReturn(aResponse().withStatus(SC_OK).withBody(readFile(apigeeGetTitlePackageResponse))) - ); - - var url = String.format(EXPORT_PACKAGE_TITLES, STUB_PROVIDER_ID, STUB_PACKAGE_ID, STUB_QUERY_PARAMS); - String actual = getWithOk(url, JOHN_USER_ID_HEADER, CONTENT_TYPE_CSV_HEADER).body().asString(); - assertThat(actual, notNullValue()); - - assertThat(actual, - Matchers.equalTo(readFile("responses/kb-ebsco/export/expected-export-three-items-zero-values.txt"))); - } - - private String titlesUrl(String year, String month, String currency, boolean publisherPlatform, - boolean previousYear) { - return "/uc/costperuse/titles?fiscalYear=%s&fiscalMonth=%s&analysisCurrency=%s&publisherPlatform=%s&previousYear=%s" - .formatted(year, month, currency, publisherPlatform, previousYear); - } - - private void mockAuthToken() { - UcAuthToken stubToken = new UcAuthToken("access_token", "Bearer", 3600L, "openid"); - stubFor(post(urlPathMatching("/oauth-proxy/token")) - .willReturn(aResponse().withStatus(SC_OK).withBody(Json.encode(stubToken))) - ); - } - - private void saveHoldingFromFile(String... holdingsArray) throws IOException, URISyntaxException { - for (int i = 0; i <= holdingsArray.length - 1; i++) { - HoldingsTestUtil.saveHolding(credentialsId, - Json.decodeValue(readFile(holdingsArray[i]), DbHoldingInfo.class), - OffsetDateTime.now(), vertx); - } - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsKbCredentialsImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsKbCredentialsImplTest.java deleted file mode 100644 index 4ca317daa..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsKbCredentialsImplTest.java +++ /dev/null @@ -1,741 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_CREATED; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_NAME; -import static org.folio.rest.impl.ResourcesTestData.STUB_MANAGED_RESOURCE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_TITLE_NAME; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; -import static org.folio.util.HoldingsRetryStatusTestUtil.getRetryStatus; -import static org.folio.util.HoldingsStatusUtil.getStatus; -import static org.folio.util.KbCredentialsTestUtil.KB_CREDENTIALS_ENDPOINT; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_URL; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_USERNAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_OTHER_HEADER; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_OTHER_ID; -import static org.folio.util.KbCredentialsTestUtil.USER_KB_CREDENTIAL_ENDPOINT; -import static org.folio.util.KbCredentialsTestUtil.getKbCredentials; -import static org.folio.util.KbCredentialsTestUtil.getKbCredentialsNonSecured; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.PackagesTestUtil.buildDbPackage; -import static org.folio.util.PackagesTestUtil.savePackage; -import static org.folio.util.ProvidersTestUtil.buildDbProvider; -import static org.folio.util.ProvidersTestUtil.saveProvider; -import static org.folio.util.ResourcesTestUtil.buildResource; -import static org.folio.util.ResourcesTestUtil.saveResource; -import static org.folio.util.TitlesTestUtil.buildTitle; -import static org.folio.util.TitlesTestUtil.saveTitle; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import org.apache.commons.collections4.map.CaseInsensitiveMap; -import org.apache.commons.lang3.StringUtils; -import org.folio.okapi.common.XOkapiHeaders; -import org.folio.repository.holdings.status.retry.RetryStatus; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.HoldingsLoadingStatus; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.KbCredentials; -import org.folio.rest.jaxrs.model.KbCredentialsCollection; -import org.folio.rest.jaxrs.model.KbCredentialsDataAttributes; -import org.folio.rest.jaxrs.model.KbCredentialsKey; -import org.folio.rest.jaxrs.model.KbCredentialsPatchRequest; -import org.folio.rest.jaxrs.model.KbCredentialsPatchRequestData; -import org.folio.rest.jaxrs.model.KbCredentialsPatchRequestDataAttributes; -import org.folio.rest.jaxrs.model.KbCredentialsPostRequest; -import org.folio.rest.jaxrs.model.KbCredentialsPutRequest; -import org.folio.rest.jaxrs.model.LoadStatusNameEnum; -import org.folio.service.kbcredentials.KbCredentialsService; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class EholdingsKbCredentialsImplTest extends WireMockTestBase { - - private static final String STARS_256 = "*".repeat(256); - private static final String OTHER_CUST_ID = "OTHER_CUST_ID"; - @Autowired - @Qualifier("nonSecuredCredentialsService") - private KbCredentialsService nonSecuredCredentialsService; - - @Autowired - private KbCredentialsService securedCredentialsService; - - @After - public void tearDown() { - clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnKbCredentialsCollectionOnGet() { - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - KbCredentialsCollection actual = getWithOk(KB_CREDENTIALS_ENDPOINT).as(KbCredentialsCollection.class); - - assertEquals(1, actual.getData().size()); - assertEquals(Integer.valueOf(1), actual.getMeta().getTotalResults()); - var credentials = actual.getData().getFirst(); - assertNotNull(credentials); - assertNotNull(credentials.getId()); - - assertEquals(STUB_API_URL, credentials.getAttributes().getUrl()); - assertEquals(STUB_CREDENTIALS_NAME, credentials.getAttributes().getName()); - assertEquals(STUB_CUSTOMER_ID, credentials.getAttributes().getCustomerId()); - assertEquals(StringUtils.repeat("*", 40), credentials.getAttributes().getApiKey()); - - assertEquals(STUB_USERNAME, credentials.getMeta().getCreatedByUsername()); - assertEquals(STUB_USER_ID, credentials.getMeta().getCreatedByUserId()); - assertNotNull(credentials.getMeta().getCreatedDate()); - } - - @Test - public void shouldReturnEmptyKbCredentialsCollectionOnGet() { - KbCredentialsCollection actual = getWithOk(KB_CREDENTIALS_ENDPOINT).as(KbCredentialsCollection.class); - - assertNotNull(actual.getData()); - assertEquals(0, actual.getData().size()); - assertEquals(Integer.valueOf(0), actual.getMeta().getTotalResults()); - } - - @Test - public void shouldReturn201OnPostIfCredentialsAreValid() { - KbCredentialsPostRequest kbCredentialsPostRequest = new KbCredentialsPostRequest() - .withData(stubbedCredentials()); - String postBody = Json.encode(kbCredentialsPostRequest); - - mockVerifyValidCredentialsRequest(); - KbCredentials actual = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_CREATED, STUB_USER_ID_HEADER) - .as(KbCredentials.class); - - assertNotNull(actual); - assertNotNull(actual.getId()); - assertNotNull(actual.getType()); - assertEquals(getWiremockUrl(), actual.getAttributes().getUrl()); - assertEquals(STUB_CREDENTIALS_NAME, actual.getAttributes().getName()); - assertEquals(STUB_CUSTOMER_ID, actual.getAttributes().getCustomerId()); - assertEquals(STUB_USER_ID, actual.getMeta().getCreatedByUserId()); - assertNotNull(actual.getMeta().getCreatedDate()); - } - - @Test - public void shouldReturn422OnPostWhenCredentialsAreInvalid() { - KbCredentialsPostRequest kbCredentialsPostRequest = new KbCredentialsPostRequest() - .withData(stubbedCredentials()); - String postBody = Json.encode(kbCredentialsPostRequest); - - mockVerifyFailedCredentialsRequest(); - JsonapiError error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "KB API Credentials are invalid"); - } - - @Test - public void shouldReturn422OnPostWhenCredentialsNameIsLongerThen255() { - KbCredentials creds = stubbedCredentials(); - creds.getAttributes().setName(STARS_256); - - KbCredentialsPostRequest kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); - String postBody = Json.encode(kbCredentialsPostRequest); - - JsonapiError error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - assertErrorContainsDetail(error, "name is too long (maximum is 255 characters)"); - } - - @Test - public void shouldReturn422OnPostWhenCredentialsNameIsEmpty() { - KbCredentials creds = stubbedCredentials(); - creds.getAttributes().setName(""); - - KbCredentialsPostRequest kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); - String postBody = Json.encode(kbCredentialsPostRequest); - - JsonapiError error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - assertErrorContainsDetail(error, "name must not be empty"); - } - - @Test - public void shouldReturn422OnPostWhenCredentialsWithProvidedNameAlreadyExist() { - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - KbCredentialsPostRequest kbCredentialsPostRequest = new KbCredentialsPostRequest() - .withData(stubbedCredentials()); - String postBody = Json.encode(kbCredentialsPostRequest); - - mockVerifyValidCredentialsRequest(); - JsonapiError error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Duplicate name"); - assertErrorContainsDetail(error, String.format("Credentials with name '%s' already exist", STUB_CREDENTIALS_NAME)); - } - - @Test - public void shouldReturn422OnPostWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() { - saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - KbCredentials creds = stubbedCredentials(); - creds.getAttributes().setName("Other KB"); - - KbCredentialsPostRequest kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); - String postBody = Json.encode(kbCredentialsPostRequest); - - mockVerifyValidCredentialsRequest(); - JsonapiError error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Duplicate credentials"); - assertErrorContainsDetail(error, String.format("Credentials with customer id '%s' and url '%s' already exist", - STUB_CUSTOMER_ID, getWiremockUrl())); - } - - @Test - public void shouldReturnKbCredentialsOnGet() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - KbCredentials actual = getWithOk(resourcePath).as(KbCredentials.class); - - assertEquals(getKbCredentials(vertx).getFirst(), actual); - } - - @Test - public void shouldReturnKbCredentialsKeyOnGet() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId + "/key"; - KbCredentialsKey actual = getWithOk(resourcePath).as(KbCredentialsKey.class); - - assertEquals(STUB_API_KEY, actual.getAttributes().getApiKey()); - } - - @Test - public void shouldReturn400OnGetWhenIdIsInvalid() { - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; - JsonapiError error = getWithStatus(resourcePath, SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); - } - - @Test - public void shouldReturn404OnGetWhenCredentialsAreMissing() { - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = getWithStatus(resourcePath, SC_NOT_FOUND).as(JsonapiError.class); - - assertErrorContainsTitle(error, "KbCredentials not found by id"); - } - - @Test - public void shouldReturn204OnPatchIfCredentialsAreValid() { - String credentialsId = - saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setCustomerId("updated"); - - String patchBody = Json.encode(kbCredentialsPatchRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - patchWithNoContent(resourcePath, patchBody, STUB_USER_ID_HEADER); - - KbCredentials actual = getKbCredentialsNonSecured(vertx).getFirst(); - - assertNotNull(actual); - assertNotNull(actual.getId()); - assertNotNull(actual.getType()); - assertEquals(getWiremockUrl(), actual.getAttributes().getUrl()); - assertEquals(STUB_API_KEY, actual.getAttributes().getApiKey()); - assertEquals(STUB_CREDENTIALS_NAME, actual.getAttributes().getName()); - assertEquals("updated", actual.getAttributes().getCustomerId()); - assertEquals(STUB_USER_ID, actual.getMeta().getCreatedByUserId()); - assertNotNull(actual.getMeta().getCreatedDate()); - assertEquals(STUB_USER_ID, actual.getMeta().getUpdatedByUserId()); - assertNotNull(actual.getMeta().getUpdatedDate()); - } - - @Test - public void shouldReturn422OnPatchWhenCredentialsAreInvalid() { - String credentialsId = - saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setCustomerId("updated"); - - String patchBody = Json.encode(kbCredentialsPatchRequest); - - mockVerifyFailedCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "KB API Credentials are invalid"); - } - - @Test - public void shouldReturn422OnPatchWhenCredentialsNameIsLongerThen255() { - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setName(STARS_256); - - String patchBody = Json.encode(kbCredentialsPatchRequest); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - assertErrorContainsDetail(error, "name is too long (maximum is 255 characters)"); - } - - @Test - public void shouldReturn422OnPatchWhenCredentialsNameIsEmpty() { - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setName(""); - kbCredentialsPatchRequest.getData().getAttributes().setCustomerId(STUB_CUSTOMER_ID); - - String patchBody = Json.encode(kbCredentialsPatchRequest); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - assertErrorContainsDetail(error, "name must not be empty"); - } - - @Test - public void shouldReturn422OnPatchWhenAllFieldsAreEmpty() { - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - String patchBody = Json.encode(kbCredentialsPatchRequest); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid attributes"); - assertErrorContainsDetail(error, "At least one of attributes must not be empty"); - } - - @Test - public void shouldReturn422OnPatchWhenCredentialsWithProvidedNameAlreadyExist() { - saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - String credentialsId = saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME + "2", - STUB_API_KEY, OTHER_CUST_ID, vertx); - - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setName(STUB_CREDENTIALS_NAME); - String patchBody = Json.encode(kbCredentialsPatchRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Duplicate name"); - assertErrorContainsDetail(error, String.format("Credentials with name '%s' already exist", STUB_CREDENTIALS_NAME)); - } - - @Test - public void shouldReturn422OnPatchWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() { - saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - final String credentialsId = saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME + "2", - STUB_API_KEY, "OTHER_CUST_ID", vertx); - - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setCustomerId(STUB_CUSTOMER_ID); - kbCredentialsPatchRequest.getData().getAttributes().setUrl(getWiremockUrl()); - String patchBody = Json.encode(kbCredentialsPatchRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Duplicate credentials"); - assertErrorContainsDetail(error, String.format("Credentials with customer id '%s' and url '%s' already exist", - STUB_CUSTOMER_ID, getWiremockUrl())); - } - - @Test - public void shouldReturn400OnPatchWhenIdIsInvalid() { - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setName(STUB_CREDENTIALS_NAME); - - String patchBody = Json.encode(kbCredentialsPatchRequest); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; - JsonapiError error = patchWithStatus(resourcePath, patchBody, SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); - } - - @Test - public void shouldReturn404OnPatchWhenCredentialsAreMissing() { - KbCredentialsPatchRequest kbCredentialsPatchRequest = stubPatchRequest(); - kbCredentialsPatchRequest.getData().getAttributes().setName(STUB_CREDENTIALS_NAME); - - String patchBody = Json.encode(kbCredentialsPatchRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = - patchWithStatus(resourcePath, patchBody, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "KbCredentials not found by id"); - } - - @Test - public void shouldReturn204OnPutIfCredentialsAreValid() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - KbCredentials creds = stubbedCredentials(); - creds.getAttributes() - .withName(STUB_CREDENTIALS_NAME + "updated") - .withCustomerId(STUB_CUSTOMER_ID + "updated"); - - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); - String putBody = Json.encode(kbCredentialsPutRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - putWithNoContent(resourcePath, putBody, STUB_USER_ID_HEADER); - - KbCredentials actual = getKbCredentials(vertx).getFirst(); - - assertNotNull(actual); - assertNotNull(actual.getId()); - assertNotNull(actual.getType()); - assertEquals(getWiremockUrl(), actual.getAttributes().getUrl()); - assertEquals(STUB_CREDENTIALS_NAME + "updated", actual.getAttributes().getName()); - assertEquals(STUB_CUSTOMER_ID + "updated", actual.getAttributes().getCustomerId()); - assertEquals(STUB_USER_ID, actual.getMeta().getCreatedByUserId()); - assertNotNull(actual.getMeta().getCreatedDate()); - assertEquals(STUB_USER_ID, actual.getMeta().getUpdatedByUserId()); - assertNotNull(actual.getMeta().getUpdatedDate()); - } - - @Test - public void shouldReturn422OnPutWhenCredentialsAreInvalid() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest() - .withData(stubbedCredentials()); - String putBody = Json.encode(kbCredentialsPutRequest); - - mockVerifyFailedCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "KB API Credentials are invalid"); - } - - @Test - public void shouldReturn422OnPutWhenCredentialsNameIsLongerThen255() { - KbCredentials creds = stubbedCredentials(); - creds.getAttributes().setName(STARS_256); - - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); - String putBody = Json.encode(kbCredentialsPutRequest); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - assertErrorContainsDetail(error, "name is too long (maximum is 255 characters)"); - } - - @Test - public void shouldReturn422OnPutWhenCredentialsNameIsEmpty() { - KbCredentials creds = stubbedCredentials(); - creds.getAttributes().setName(""); - - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); - String putBody = Json.encode(kbCredentialsPutRequest); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - assertErrorContainsDetail(error, "name must not be empty"); - } - - @Test - public void shouldReturn422OnPutWhenCredentialsWithProvidedNameAlreadyExist() { - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - String credentialsId = saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME + "2", - STUB_API_KEY, OTHER_CUST_ID, vertx); - - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest() - .withData(stubbedCredentials()); - String putBody = Json.encode(kbCredentialsPutRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Duplicate name"); - assertErrorContainsDetail(error, String.format("Credentials with name '%s' already exist", STUB_CREDENTIALS_NAME)); - } - - @Test - public void shouldReturn422OnPutWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() { - saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - String credentialsId = saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME + "2", - STUB_API_KEY, OTHER_CUST_ID, vertx); - - KbCredentials creds = stubbedCredentials(); - creds.getAttributes().setName(STUB_CREDENTIALS_NAME + "2"); - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); - String putBody = Json.encode(kbCredentialsPutRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - JsonapiError error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Duplicate credentials"); - assertErrorContainsDetail(error, String.format("Credentials with customer id '%s' and url '%s' already exist", - STUB_CUSTOMER_ID, getWiremockUrl())); - } - - @Test - public void shouldReturn400OnPutWhenIdIsInvalid() { - KbCredentials creds = stubbedCredentials(); - creds.setId(UUID.randomUUID().toString()); - - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); - String putBody = Json.encode(kbCredentialsPutRequest); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; - JsonapiError error = putWithStatus(resourcePath, putBody, SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); - } - - @Test - public void shouldReturn404OnPutWhenCredentialsAreMissing() { - KbCredentials creds = stubbedCredentials(); - creds.setId(UUID.randomUUID().toString()); - - KbCredentialsPutRequest kbCredentialsPutRequest = new KbCredentialsPutRequest().withData(creds); - String putBody = Json.encode(kbCredentialsPutRequest); - - mockVerifyValidCredentialsRequest(); - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - JsonapiError error = putWithStatus(resourcePath, putBody, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "KbCredentials not found by id"); - } - - @Test - public void shouldReturn204OnDelete() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - deleteWithNoContent(resourcePath); - - List<KbCredentials> kbCredentialsInDb = getKbCredentials(vertx); - assertTrue(kbCredentialsInDb.isEmpty()); - } - - @Test - public void shouldReturn204OnDeleteWhenHasRelatedRecords() { - String credentialsId = saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, - vertx); - - saveAssignedUser(STUB_USER_ID, credentialsId, vertx); - saveProvider(buildDbProvider(STUB_VENDOR_ID, credentialsId, STUB_VENDOR_NAME), vertx); - savePackage(buildDbPackage(FULL_PACKAGE_ID, credentialsId, STUB_PACKAGE_NAME), vertx); - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, credentialsId, STUB_TITLE_NAME), vertx); - saveTitle(buildTitle(STUB_TITLE_ID, credentialsId, STUB_TITLE_NAME), vertx); - - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - deleteWithNoContent(resourcePath); - - List<KbCredentials> kbCredentialsInDb = getKbCredentials(vertx); - assertTrue(kbCredentialsInDb.isEmpty()); - } - - @Test - public void shouldReturn204OnDeleteWhenCredentialsAreMissing() { - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - deleteWithNoContent(resourcePath); - - List<KbCredentials> kbCredentialsInDb = getKbCredentials(vertx); - assertTrue(kbCredentialsInDb.isEmpty()); - } - - @Test - public void shouldReturn400OnDeleteWhenIdIsInvalid() { - String resourcePath = KB_CREDENTIALS_ENDPOINT + "/invalid-id"; - JsonapiError error = deleteWithStatus(resourcePath, SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "parameter value {invalid-id} is not valid: must match"); - } - - @Test - public void shouldReturn200AndKbCredentialsOnGetByUser() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - saveAssignedUser(STUB_USER_ID, credentialsId, vertx); - - KbCredentials actual = - getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_OK, STUB_USER_ID_HEADER).as(KbCredentials.class); - assertEquals(getKbCredentialsNonSecured(vertx).getFirst(), actual); - } - - @Test - public void shouldReturn200AndKbCredentialsOnGetByUserWhenSingleKbCredentialsPresent() { - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - - KbCredentials actual = - getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_OK, STUB_USER_ID_HEADER).as(KbCredentials.class); - assertEquals(getKbCredentialsNonSecured(vertx).getFirst(), actual); - } - - @Test - public void shouldReturn404OnGetByUserWhenAssignedUserIsMissingAndNoKbCredentialsAtAll() { - JsonapiError error = - getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "KB Credentials do not exist "); - } - - @Test - public void shouldReturn404OnGetByUserWhenUserIsNotTheOneWhoIsAssigned() { - String credentialsId = - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - saveAssignedUser(STUB_USER_ID, credentialsId, vertx); - - JsonapiError error = getWithStatus(USER_KB_CREDENTIAL_ENDPOINT, SC_NOT_FOUND, STUB_USER_ID_OTHER_HEADER).as( - JsonapiError.class); - - assertErrorContainsTitle(error, "KB Credentials do not exist or user with userId = " + STUB_USER_OTHER_ID - + " is not assigned to any available knowledgebase."); - } - - @Test - public void shouldReturnStatusNotStartedOnKbCredentialsCreation() { - KbCredentialsPostRequest kbCredentialsPostRequest = new KbCredentialsPostRequest() - .withData(stubbedCredentials()); - String postBody = Json.encode(kbCredentialsPostRequest); - - mockVerifyValidCredentialsRequest(); - KbCredentials actual = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_CREATED, STUB_USER_ID_HEADER) - .as(KbCredentials.class); - - final HoldingsLoadingStatus status = getStatus(actual.getId(), vertx); - assertEquals(LoadStatusNameEnum.NOT_STARTED, status.getData().getAttributes().getStatus().getName()); - - final RetryStatus retryStatus = getRetryStatus(actual.getId(), vertx); - assertThat(retryStatus, notNullValue()); - } - - @Test - public void shouldReturnSecuredCollection() { - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - Map<String, String> headers = new CaseInsensitiveMap<>(); - headers.put(XOkapiHeaders.TENANT, STUB_TENANT); - KbCredentialsCollection collection = securedCredentialsService.findAll(headers).join(); - assertThat(collection.getMeta().getTotalResults(), equalTo(1)); - var credentials = collection.getData().getFirst(); - assertThat(credentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(credentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(credentials.getAttributes().getApiKey(), containsString("*")); - assertThat(credentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(credentials.getAttributes().getUrl(), equalTo(STUB_API_URL)); - } - - @Test - public void shouldReturnNonSecuredCollection() { - saveKbCredentials(STUB_API_URL, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); - Map<String, String> headers = new CaseInsensitiveMap<>(); - headers.put(XOkapiHeaders.TENANT, STUB_TENANT); - KbCredentialsCollection collection = nonSecuredCredentialsService.findAll(headers).join(); - assertThat(collection.getMeta().getTotalResults(), equalTo(1)); - var credentials = collection.getData().getFirst(); - assertThat(credentials.getType(), equalTo(KbCredentials.Type.KB_CREDENTIALS)); - assertThat(credentials.getAttributes().getName(), equalTo(STUB_CREDENTIALS_NAME)); - assertThat(credentials.getAttributes().getApiKey(), equalTo(STUB_API_KEY)); - assertThat(credentials.getAttributes().getCustomerId(), equalTo(STUB_CUSTOMER_ID)); - assertThat(credentials.getAttributes().getUrl(), equalTo(STUB_API_URL)); - } - - private KbCredentials stubbedCredentials() { - return new KbCredentials() - .withType(KbCredentials.Type.KB_CREDENTIALS) - .withAttributes(new KbCredentialsDataAttributes() - .withName(STUB_CREDENTIALS_NAME) - .withCustomerId(STUB_CUSTOMER_ID) - .withApiKey(STUB_API_KEY) - .withUrl(getWiremockUrl())); - } - - private KbCredentialsPatchRequest stubPatchRequest() { - return new KbCredentialsPatchRequest().withData( - new KbCredentialsPatchRequestData().withType(KbCredentialsPatchRequestData.Type.KB_CREDENTIALS) - .withAttributes(new KbCredentialsPatchRequestDataAttributes()) - ); - } - - private void mockVerifyValidCredentialsRequest() { - stubFor( - get(urlPathMatching("/rm/rmaccounts/.*")) - .willReturn(aResponse().withStatus(SC_OK).withBody("{\"totalResults\": 0, \"vendors\": []}"))); - } - - private void mockVerifyFailedCredentialsRequest() { - stubFor( - get(urlPathMatching("/rm/rmaccounts/.*")) - .willReturn(aResponse().withStatus(SC_UNAUTHORIZED))); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java deleted file mode 100644 index 498be798d..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java +++ /dev/null @@ -1,1343 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; -import static java.lang.String.format; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_FORBIDDEN; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.RecordType.PACKAGE; -import static org.folio.repository.RecordType.RESOURCE; -import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; -import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.repository.packages.PackageTableConstants.PACKAGES_TABLE_NAME; -import static org.folio.repository.resources.ResourceTableConstants.RESOURCES_TABLE_NAME; -import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID_2; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID_3; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_CONTENT_TYPE; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID_2; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME_2; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.ResourcesTestData.STUB_MANAGED_RESOURCE_ID; -import static org.folio.rest.impl.ResourcesTestData.STUB_MANAGED_RESOURCE_ID_2; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE_2; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE_3; -import static org.folio.test.util.TestUtil.getFile; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.mockPost; -import static org.folio.test.util.TestUtil.mockPut; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME; -import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME_2; -import static org.folio.util.AccessTypesTestUtil.getAccessTypeMappings; -import static org.folio.util.AccessTypesTestUtil.insertAccessType; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; -import static org.folio.util.AccessTypesTestUtil.testData; -import static org.folio.util.AssertTestUtil.assertEqualsPackageId; -import static org.folio.util.AssertTestUtil.assertEqualsUuid; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.getDefaultKbConfiguration; -import static org.folio.util.KbTestUtil.setupDefaultKbConfiguration; -import static org.folio.util.PackagesTestUtil.buildDbPackage; -import static org.folio.util.PackagesTestUtil.savePackage; -import static org.folio.util.PackagesTestUtil.setUpPackages; -import static org.folio.util.ResourcesTestUtil.buildResource; -import static org.folio.util.TagsTestUtil.saveTag; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.equalToIgnoringCase; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.AnythingPattern; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Objects; -import org.apache.http.HttpStatus; -import org.folio.holdingsiq.model.CoverageDates; -import org.folio.holdingsiq.model.PackageByIdData; -import org.folio.holdingsiq.model.PackageData; -import org.folio.holdingsiq.model.PackagePut; -import org.folio.repository.accesstypes.AccessTypeMapping; -import org.folio.repository.packages.DbPackage; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.AccessType; -import org.folio.rest.jaxrs.model.ContentType; -import org.folio.rest.jaxrs.model.Errors; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.KbCredentials; -import org.folio.rest.jaxrs.model.MetaTotalResults; -import org.folio.rest.jaxrs.model.Package; -import org.folio.rest.jaxrs.model.PackageCollection; -import org.folio.rest.jaxrs.model.PackageCollectionItem; -import org.folio.rest.jaxrs.model.PackagePostRequest; -import org.folio.rest.jaxrs.model.PackagePutRequest; -import org.folio.rest.jaxrs.model.PackageTags; -import org.folio.rest.jaxrs.model.PackageTagsPutRequest; -import org.folio.rest.jaxrs.model.ResourceCollection; -import org.folio.rest.jaxrs.model.ResourceCollectionItem; -import org.folio.rest.jaxrs.model.Tags; -import org.folio.util.AccessTypesTestUtil; -import org.folio.util.PackagesTestUtil; -import org.folio.util.ResourcesTestUtil; -import org.folio.util.TagsTestUtil; -import org.json.JSONException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.skyscreamer.jsonassert.JSONAssert; - -@RunWith(VertxUnitRunner.class) -public class EholdingsPackagesTest extends WireMockTestBase { - - private static final String PACKAGE_STUB_FILE = "responses/rmapi/packages/get-package-by-id-response.json"; - private static final String PACKAGE_2_STUB_FILE = "responses/rmapi/packages/get-package-by-id-2-response.json"; - private static final String CUSTOM_PACKAGE_STUB_FILE = - "responses/rmapi/packages/get-custom-package-by-id-response.json"; - private static final String RESOURCES_BY_PACKAGE_ID_STUB_FILE = - "responses/rmapi/resources/get-resources-by-package-id-response.json"; - private static final String RESOURCES_BY_PACKAGE_ID_EMPTY_STUB_FILE = - "responses/rmapi/resources/get-resources-by-package-id-response-empty.json"; - private static final String RESOURCES_BY_PACKAGE_ID_EMPTY_CUSTOMER_RESOURCE_LIST_STUB_FILE = - "responses/rmapi/resources/get-resources-by-package-id-response-empty-customer-list.json"; - private static final String EXPECTED_PACKAGE_BY_ID_STUB_FILE = - "responses/kb-ebsco/packages/expected-package-by-id.json"; - private static final String EXPECTED_RESOURCES_STUB_FILE = - "responses/kb-ebsco/resources/expected-resources-by-package-id.json"; - private static final String EXPECTED_RESOURCES_WITH_TAGS_STUB_FILE = - "responses/kb-ebsco/resources/expected-resources-by-package-id-with-tags.json"; - private static final String VENDOR_BY_PACKAGE_ID_STUB_FILE = - "responses/rmapi/vendors/get-vendor-by-id-for-package.json"; - - private static final String PACKAGES_ENDPOINT = "eholdings/packages"; - private static final String PACKAGES_PATH = PACKAGES_ENDPOINT + "/" + FULL_PACKAGE_ID; - private static final String PACKAGE_TAGS_PATH = PACKAGES_PATH + "/tags"; - private static final String PACKAGE_RESOURCES_PATH = PACKAGES_PATH + "/resources"; - private static final String PACKAGES_BULK_FETCH_PATH = "/eholdings/packages/bulk/fetch"; - - private static final String PACKAGES_STUB_URL = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages"; - private static final String PACKAGE_BY_ID_URL = PACKAGES_STUB_URL + "/" + STUB_PACKAGE_ID; - private static final UrlPathPattern PACKAGE_URL_PATTERN = - new UrlPathPattern(new EqualToPattern(PACKAGE_BY_ID_URL), false); - private static final String RESOURCES_BY_PACKAGE_ID_URL = PACKAGE_BY_ID_URL + "/titles"; - private static final String PACKAGE_BY_ID_2_URL = PACKAGES_STUB_URL + "/" + STUB_PACKAGE_ID_2; - private static final String PACKAGE_UPDATED_STATE = "Package updated"; - private static final String GET_PACKAGE_SCENARIO = "Get package"; - private static final String STUB_TITLE_NAME = "Activity Theory Perspectives on Technology in Higher Education"; - - private final ObjectMapper mapper = new ObjectMapper(); - private KbCredentials configuration; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - configuration = getDefaultKbConfiguration(vertx); - } - - @After - public void tearDown() { - clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); - clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); - clearDataFromTable(vertx, TAGS_TABLE_NAME); - clearDataFromTable(vertx, RESOURCES_TABLE_NAME); - clearDataFromTable(vertx, PACKAGES_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnPackagesOnGet() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/packages/get-packages-response.json"; - - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/packages.*"), stubResponseFile); - - String packages = getWithOk(PACKAGES_ENDPOINT + "?q=American&filter[type]=abstractandindex&count=5", - STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals(readFile("responses/kb-ebsco/packages/expected-package-collection-with-five-elements.json"), - packages, false); - } - - @Test - public void shouldReturnPackagesOnSearchByTagsOnly() throws IOException, URISyntaxException { - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE_2); - saveTag(vertx, FULL_PACKAGE_ID_3, PACKAGE, STUB_TAG_VALUE_3); - - setUpPackages(vertx, configuration.getId()); - - PackageCollection packageCollection = getWithOk( - PACKAGES_ENDPOINT + "?filter[tags]=" + STUB_TAG_VALUE + "&filter[tags]=" + STUB_TAG_VALUE_2, STUB_USER_ID_HEADER) - .as(PackageCollection.class); - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(2, packages.size()); - assertEquals(STUB_PACKAGE_NAME, packages.get(0).getAttributes().getName()); - assertEquals(STUB_PACKAGE_NAME_2, packages.get(1).getAttributes().getName()); - } - - @Test - public void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByTags() { - savePackage(buildDbPackage(FULL_PACKAGE_ID, configuration.getId(), STUB_PACKAGE_NAME), vertx); - savePackage(buildDbPackage(FULL_PACKAGE_ID_2, configuration.getId(), STUB_PACKAGE_NAME_2), vertx); - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); - - mockGet(new RegexPattern(".*vendors/.*/packages/.*"), HttpStatus.SC_INTERNAL_SERVER_ERROR); - - PackageCollection packageCollection = getWithOk(PACKAGES_ENDPOINT + "?filter[tags]=" + STUB_TAG_VALUE, - STUB_USER_ID_HEADER).as(PackageCollection.class); - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(0, packages.size()); - } - - @Test - public void shouldReturnPackagesOnSearchWithPagination() throws IOException, URISyntaxException { - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_3, PACKAGE, STUB_TAG_VALUE); - - setUpPackages(vertx, configuration.getId()); - - PackageCollection packageCollection = getWithOk( - PACKAGES_ENDPOINT + "?page=2&count=1&filter[tags]=" + STUB_TAG_VALUE, STUB_USER_ID_HEADER) - .as(PackageCollection.class); - - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(3, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(1, packages.size()); - assertEquals(STUB_PACKAGE_NAME_2, packages.getFirst().getAttributes().getName()); - } - - @Test - public void shouldReturnPackagesOnSearchByAccessTypeWithPagination() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.get(0).getId(), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID_2, PACKAGE, accessTypes.get(1).getId(), vertx); - - setUpPackages(vertx, configuration.getId()); - - String resourcePath = PACKAGES_ENDPOINT + "?page=2&count=1&filter[access-type]=" - + STUB_ACCESS_TYPE_NAME + "&filter[access-type]=" + STUB_ACCESS_TYPE_NAME_2; - PackageCollection packageCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(PackageCollection.class); - - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(1, packages.size()); - assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getAttributes().getName()); - } - - @Test - public void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByAccessType() { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.getFirst().getId(), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID_2, PACKAGE, accessTypes.getFirst().getId(), vertx); - - mockGet(new RegexPattern(".*vendors/.*/packages/.*"), HttpStatus.SC_INTERNAL_SERVER_ERROR); - - String resourcePath = PACKAGES_ENDPOINT + "?filter[access-type]=" + STUB_ACCESS_TYPE_NAME; - PackageCollection packageCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(PackageCollection.class); - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(0, packages.size()); - } - - @Test - public void shouldReturn400OnInvalidFilterCustomParameter() { - String invalidParameterForFilterCustom = getWithStatus( - PACKAGES_ENDPOINT + "?filter[custom]=test", 400, STUB_USER_ID_HEADER).asString(); - - assertTrue( - invalidParameterForFilterCustom.contains("Invalid Query Parameter for filter[custom]: only 'true' is supported")); - } - - @Test - public void shouldReturn400OnNotSupportedFilterCustomParameter() { - String falseParameterForFilterCustom = getWithStatus( - PACKAGES_ENDPOINT + "?filter[custom]=false", 400, STUB_USER_ID_HEADER).asString(); - - assertTrue( - falseParameterForFilterCustom.contains("Invalid Query Parameter for filter[custom]: only 'true' is supported")); - } - - @Test - public void shouldReturnPackagesOnGetWithPackageId() throws IOException, URISyntaxException, JSONException { - String packagesStubResponseFile = "responses/rmapi/packages/get-packages-by-provider-id.json"; - String providerIdByCustIdStubResponseFile = "responses/rmapi/proxiescustomlabels/get-success-response.json"; - - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/"), providerIdByCustIdStubResponseFile); - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages.*"), - packagesStubResponseFile); - - String packages = getWithOk(PACKAGES_ENDPOINT + "?q=a&count=5&page=1&filter[custom]=true", STUB_USER_ID_HEADER) - .asString(); - - JSONAssert.assertEquals(readFile("responses/kb-ebsco/packages/expected-package-collection-with-one-element.json"), - packages, false); - } - - @Test - public void shouldReturnPackagesOnGetById() throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - - String packageData = getWithOk(PACKAGES_PATH, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(EXPECTED_PACKAGE_BY_ID_STUB_FILE), packageData, false); - } - - @Test - public void shouldReturnPackageWithTagOnGetById() throws IOException, URISyntaxException { - String packageId = FULL_PACKAGE_ID; - saveTag(vertx, packageId, PACKAGE, STUB_TAG_VALUE); - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - - Package packageData = getWithOk(PACKAGES_ENDPOINT + "/" + packageId, STUB_USER_ID_HEADER).as(Package.class); - - assertTrue(packageData.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); - } - - @Test - public void shouldReturnPackageWithAccessTypeOnGetById() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - String expectedAccessTypeId = accessTypes.getFirst().getId(); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, expectedAccessTypeId, vertx); - - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - Package packageData = getWithOk(PACKAGES_ENDPOINT + "/" + FULL_PACKAGE_ID, STUB_USER_ID_HEADER).as(Package.class); - - assertNotNull(packageData.getIncluded()); - assertEquals(expectedAccessTypeId, packageData.getData().getRelationships().getAccessType().getData().getId()); - assertEquals(expectedAccessTypeId, ((LinkedHashMap<?, ?>) packageData.getIncluded().getFirst()).get("id")); - } - - @Test - public void shouldAddPackageTagsOnPutTagsWhenPackageAlreadyHasTags() throws IOException, URISyntaxException { - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); - List<String> newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); - sendPutTags(Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); - List<String> tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); - assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); - } - - @Test - public void shouldAddPackageDataOnPutTags() throws IOException, URISyntaxException { - List<String> tags = Collections.singletonList(STUB_TAG_VALUE); - sendPutTags(tags); - List<DbPackage> packages = PackagesTestUtil.getPackages(vertx); - assertEquals(1, packages.size()); - assertEqualsPackageId(packages.getFirst().getId()); - assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getName()); - assertThat(packages.getFirst().getContentType(), equalToIgnoringCase(STUB_PACKAGE_CONTENT_TYPE)); - } - - @Test - public void shouldUpdateTagsOnlyOnPutPackageTagsEndpoint() throws IOException, URISyntaxException { - List<String> tags = Collections.singletonList(STUB_TAG_VALUE); - sendPutTags(tags); - final Package updatedPackage = sendPut(readFile(PACKAGE_STUB_FILE)); - - List<String> packageTags = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); - assertThat(packageTags, is(tags)); - assertTrue(Objects.isNull(updatedPackage.getData().getAttributes().getTags())); - } - - @Test - public void shouldDeleteAllPackageTagsOnPutTagsWhenRequestHasEmptyListOfTags() - throws IOException, URISyntaxException { - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, "test one"); - sendPutTags(Collections.emptyList()); - List<String> tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); - assertThat(tagsAfterRequest, empty()); - } - - @Test - public void shouldDoNothingOnPutWhenRequestHasNotTags() throws IOException, URISyntaxException { - sendPutTags(null); - sendPutTags(null); - List<String> tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); - assertThat(tagsAfterRequest, empty()); - } - - @Test - public void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() throws IOException, URISyntaxException { - PackageTagsPutRequest tags = - mapper.readValue(getFile("requests/kb-ebsco/package/put-package-tags.json"), PackageTagsPutRequest.class); - tags.getData().getAttributes().setName(""); - JsonapiError error = - putWithStatus(PACKAGE_TAGS_PATH, mapper.writeValueAsString(tags), SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - } - - @Test - public void shouldDeletePackageTagsOnDelete() throws IOException, URISyntaxException { - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, "test one"); - - mockGet(new EqualToPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - - var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - mockPut(new EqualToPattern(PACKAGE_BY_ID_URL), putBodyPattern, SC_NO_CONTENT); - - deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); - - List<String> tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PACKAGE); - assertThat(tagsAfterRequest, empty()); - } - - @Test - public void shouldDeletePackageAccessTypeMappingOnDelete() throws IOException, URISyntaxException { - String accessTypeId = insertAccessTypes(testData(configuration.getId()), vertx).getFirst().getId(); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypeId, vertx); - - mockGet(new EqualToPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - - var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - mockPut(new EqualToPattern(PACKAGE_BY_ID_URL), putBodyPattern, SC_NO_CONTENT); - - deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); - - List<AccessTypeMapping> mappingsAfterRequest = AccessTypesTestUtil.getAccessTypeMappings(vertx); - assertThat(mappingsAfterRequest, empty()); - } - - @Test - public void shouldDeletePackageOnDeleteRequest() throws IOException, URISyntaxException { - sendPost(readFile("requests/kb-ebsco/package/post-package-request.json")); - sendPutTags(Collections.singletonList(STUB_TAG_VALUE)); - - mockGet(new EqualToPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - mockPut(new EqualToPattern(PACKAGE_BY_ID_URL), new AnythingPattern(), SC_NO_CONTENT); - - deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); - - List<DbPackage> packages = PackagesTestUtil.getPackages(vertx); - assertThat(packages, is(empty())); - } - - @Test - public void shouldReturn404WhenPackageIsNotFoundOnRmApi() { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), SC_NOT_FOUND); - - JsonapiError error = getWithStatus(PACKAGES_PATH, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "not found"); - } - - @Test - public void shouldReturnResourcesWhenIncludedFlagIsSetToResources() - throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); - - Package packageData = getWithOk(PACKAGES_PATH + "?include=resources", STUB_USER_ID_HEADER) - .as(Package.class); - - Package expectedPackage = mapper.readValue(readFile(EXPECTED_PACKAGE_BY_ID_STUB_FILE), Package.class); - ResourceCollection expectedResources = - mapper.readValue(readFile(EXPECTED_RESOURCES_STUB_FILE), ResourceCollection.class); - expectedPackage.getIncluded().addAll(expectedResources.getData()); - - JSONAssert.assertEquals(mapper.writeValueAsString(expectedPackage), mapper.writeValueAsString(packageData), false); - } - - @Test - public void shouldReturnProviderWhenIncludedFlagIsSetToProvider() - throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID), - VENDOR_BY_PACKAGE_ID_STUB_FILE); - - String actual = getWithOk(PACKAGES_PATH + "?include=provider", STUB_USER_ID_HEADER).asString(); - - String expected = readFile("responses/kb-ebsco/packages/expected-package-by-id-with-provider.json"); - JSONAssert.assertEquals(expected, actual, false); - } - - @Test - public void shouldSendDeleteRequestForPackage() throws IOException, URISyntaxException { - var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - - mockGet(new EqualToPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - - mockPut(new EqualToPattern(PACKAGE_BY_ID_URL), putBodyPattern, SC_NO_CONTENT); - - deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); - - verify(1, putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(putBodyPattern)); - } - - @Test - public void shouldReturn400WhenPackageIdIsInvalid() { - String error = deleteWithStatus(PACKAGES_ENDPOINT + "/abc-def", SC_BAD_REQUEST, STUB_USER_ID_HEADER) - .asString(); - - assertThat(error, containsString("Package or provider id are invalid")); - } - - @Test - public void shouldReturn400WhenPackageIsNotCustom() throws URISyntaxException, IOException { - PackageData packageData = mapper.readValue(getFile(CUSTOM_PACKAGE_STUB_FILE), PackageData.class) - .toBuilder().isCustom(false).build(); - - stubFor( - get(PACKAGE_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder() - .withBody(mapper.writeValueAsString(packageData)))); - - JsonapiError error = deleteWithStatus(PACKAGES_PATH, SC_BAD_REQUEST, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Package cannot be deleted"); - } - - @Test - public void shouldReturn200WhenSelectingPackage() throws URISyntaxException, IOException { - boolean updatedIsSelected = true; - - PackageByIdData packageData = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageByIdData.class); - packageData = packageData.toByIdBuilder().isSelected(updatedIsSelected).build(); - String updatedPackageValue = mapper.writeValueAsString(packageData); - mockUpdateScenario(readFile(PACKAGE_STUB_FILE), updatedPackageValue); - - Package actualPackage = putWithOk(PACKAGES_PATH, readFile("requests/kb-ebsco/package/put-package-selected.json"), - STUB_USER_ID_HEADER).as(Package.class); - - assertEquals(updatedIsSelected, actualPackage.getData().getAttributes().getIsSelected()); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-is-selected.json"), true, true))); - } - - @Test - public void shouldUpdateAllAttributesInSelectedPackage() throws URISyntaxException, IOException { - boolean updatedSelected = true; - boolean updatedAllowEbscoToAddTitles = true; - boolean updatedHidden = true; - String updatedBeginCoverage = "2003-01-01"; - String updatedEndCoverage = "2004-01-01"; - - var updatedPackageValue = preparePackageData(updatedSelected, updatedBeginCoverage, updatedEndCoverage, - updatedAllowEbscoToAddTitles, updatedHidden); - mockUpdateScenario(readFile(PACKAGE_STUB_FILE), updatedPackageValue); - - Package actualPackage = putWithOk(PACKAGES_PATH, - readFile("requests/kb-ebsco/package/put-package-selected.json"), STUB_USER_ID_HEADER).as(Package.class); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-is-selected.json"), true, true))); - - assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); - assertEquals(updatedAllowEbscoToAddTitles, actualPackage.getData().getAttributes().getAllowKbToAddTitles()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); - assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); - assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); - } - - @Test - @SuppressWarnings("checkstyle:methodLength") - public void shouldUpdateAllAttributesInSelectedPackageAndCreateNewAccessTypeMapping() - throws URISyntaxException, IOException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - String accessTypeId = accessTypes.getFirst().getId(); - - boolean updatedSelected = true; - boolean updatedAllowEbscoToAddTitles = true; - boolean updatedHidden = true; - String updatedBeginCoverage = "2003-01-01"; - String updatedEndCoverage = "2004-01-01"; - - var updatedPackageValue = preparePackageData(updatedSelected, updatedBeginCoverage, updatedEndCoverage, - updatedAllowEbscoToAddTitles, updatedHidden); - mockUpdateScenario(readFile(PACKAGE_STUB_FILE), updatedPackageValue); - - String putBody = format(readFile("requests/kb-ebsco/package/put-package-selected-with-access-type.json"), - accessTypeId); - Package actualPackage = putWithOk(PACKAGES_PATH, putBody, STUB_USER_ID_HEADER).as(Package.class); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-is-selected.json"), true, true))); - - assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); - assertEquals(updatedAllowEbscoToAddTitles, actualPackage.getData().getAttributes().getAllowKbToAddTitles()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); - assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); - assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(1, accessTypeMappingsInDb.size()); - assertEquals(actualPackage.getData().getId(), accessTypeMappingsInDb.getFirst().getRecordId()); - assertEqualsUuid(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); - assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); - assertNotNull(actualPackage.getIncluded()); - assertEquals(accessTypeId, actualPackage.getData().getRelationships().getAccessType().getData().getId()); - assertEquals(accessTypeId, ((LinkedHashMap<?, ?>) actualPackage.getIncluded().getFirst()).get("id")); - } - - @Test - public void shouldDeleteAccessTypeMappingWhenRmApiSend404() throws URISyntaxException, IOException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - String currentAccessTypeId = accessTypes.get(0).getId(); - String newAccessTypeId = accessTypes.get(1).getId(); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, currentAccessTypeId, vertx); - - PackageByIdData packageData = mapper - .readValue(getFile(CUSTOM_PACKAGE_STUB_FILE), PackageByIdData.class) - .toByIdBuilder() - .contentType("streamingmedia") - .build(); - - String updatedPackageValue = mapper.writeValueAsString(packageData); - mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); - - String putBody = format(readFile("requests/kb-ebsco/package/put-package-custom-with-access-type.json"), - newAccessTypeId); - stubFor(get(PACKAGE_URL_PATTERN).inScenario("Put package") - .whenScenarioStateIs(STARTED) - .willReturn(new ResponseDefinitionBuilder().withBody(readFile(CUSTOM_PACKAGE_STUB_FILE))) - .willSetStateTo("Not found")); - stubFor(get(PACKAGE_URL_PATTERN).inScenario("Put package") - .whenScenarioStateIs("Not found") - .willReturn(new ResponseDefinitionBuilder().withStatus(SC_NOT_FOUND))); - - putWithStatus(PACKAGES_PATH, putBody, SC_NOT_FOUND, STUB_USER_ID_HEADER); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(0, accessTypeMappingsInDb.size()); - } - - @Test - public void shouldReturn422OnPutWhenUnselectNonCustomPackageIsHidden() throws URISyntaxException, IOException { - String putBody = readFile("requests/kb-ebsco/package/put-package-not-selected-non-empty-fields.json"); - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), PACKAGE_STUB_FILE); - JsonapiError error = putWithStatus(PACKAGES_PATH, putBody, SC_UNPROCESSABLE_ENTITY, CONTENT_TYPE_HEADER, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - verify(0, putRequestedFor(PACKAGE_URL_PATTERN)); - - assertErrorContainsTitle(error, "Invalid visibilityData.isHidden"); - } - - @Test - public void shouldReturn422OnPutWhenCustomPackageUpdateLikeNotCustom() throws URISyntaxException, IOException { - String putBody = readFile("requests/kb-ebsco/package/put-package-selected.json"); - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - JsonapiError error = putWithStatus(PACKAGES_PATH, putBody, SC_UNPROCESSABLE_ENTITY, CONTENT_TYPE_HEADER, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - verify(0, putRequestedFor(PACKAGE_URL_PATTERN)); - - assertErrorContainsTitle(error, "Package isCustom not matched"); - } - - @Test - public void shouldPassIsFullPackageAttributeToRmApi() throws URISyntaxException, IOException { - PackageByIdData updatedPackage = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageByIdData.class) - .toByIdBuilder().isSelected(true).build(); - - mockUpdateScenario(readFile(PACKAGE_STUB_FILE), mapper.writeValueAsString(updatedPackage)); - - PackagePutRequest request = - mapper.readValue(readFile("requests/kb-ebsco/package/put-package-selected.json"), PackagePutRequest.class); - request.getData().getAttributes().setIsFullPackage(false); - putWithOk(PACKAGES_PATH, mapper.writeValueAsString(request), STUB_USER_ID_HEADER).as(Package.class); - - PackagePut rmApiPutRequest = - mapper.readValue(readFile("requests/rmapi/packages/put-package-is-selected.json"), PackagePut.class) - .toBuilder().isFullPackage(false).build(); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(mapper.writeValueAsString(rmApiPutRequest), true, true))); - } - - @Test - public void shouldUpdateAllAttributesInCustomPackage() throws URISyntaxException, IOException { - boolean updatedSelected = true; - boolean updatedHidden = true; - String updatedBeginCoverage = "2003-01-01"; - String updatedEndCoverage = "2004-01-01"; - String updatedPackageName = "name of the ages forever and ever"; - - var updatedPackageValue = - prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, updatedEndCoverage, - updatedPackageName); - mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); - - Package actualPackage = putWithOk(PACKAGES_PATH, - readFile("requests/kb-ebsco/package/put-package-custom-multiple-attributes.json"), - STUB_USER_ID_HEADER).as(Package.class); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), true, true))); - - assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); - assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); - assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); - assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); - assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); - } - - @Test - @SuppressWarnings("checkstyle:methodLength") - public void shouldUpdateAllAttributesInCustomPackageAndCreateNewAccessTypeMapping() - throws URISyntaxException, IOException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - String accessTypeId = accessTypes.getFirst().getId(); - - boolean updatedSelected = true; - boolean updatedHidden = true; - String updatedBeginCoverage = "2003-01-01"; - String updatedEndCoverage = "2004-01-01"; - String updatedPackageName = "name of the ages forever and ever"; - - var updatedPackageValue = prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, - updatedEndCoverage, updatedPackageName); - mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); - - String putBody = format(readFile("requests/kb-ebsco/package/put-package-custom-with-access-type.json"), - accessTypeId); - Package actualPackage = putWithOk(PACKAGES_PATH, putBody, STUB_USER_ID_HEADER).as(Package.class); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), true, true))); - - assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); - assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); - assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); - assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); - assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(1, accessTypeMappingsInDb.size()); - assertEquals(actualPackage.getData().getId(), accessTypeMappingsInDb.getFirst().getRecordId()); - assertEqualsUuid(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); - assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); - assertNotNull(actualPackage.getIncluded()); - assertEquals(accessTypeId, actualPackage.getData().getRelationships().getAccessType().getData().getId()); - assertEquals(accessTypeId, ((LinkedHashMap<?, ?>) actualPackage.getIncluded().getFirst()).get("id")); - } - - @Test - @SuppressWarnings("checkstyle:methodLength") - public void shouldUpdateAllAttributesInCustomPackageAndDeleteAccessTypeMapping() - throws URISyntaxException, IOException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - String accessTypeId = accessTypes.getFirst().getId(); - - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypeId, vertx); - - boolean updatedSelected = true; - boolean updatedHidden = true; - String updatedBeginCoverage = "2003-01-01"; - String updatedEndCoverage = "2004-01-01"; - String updatedPackageName = "name of the ages forever and ever"; - - var updatedPackageValue = prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, - updatedEndCoverage, updatedPackageName); - mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); - - String putBody = readFile("requests/kb-ebsco/package/put-package-custom-multiple-attributes.json"); - Package actualPackage = putWithOk(PACKAGES_PATH, putBody, STUB_USER_ID_HEADER).as(Package.class); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), true, true))); - - assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); - assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); - assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); - assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); - assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(0, accessTypeMappingsInDb.size()); - - assertNotNull(actualPackage.getIncluded()); - assertEquals(0, actualPackage.getIncluded().size()); - assertNull(actualPackage.getData().getRelationships().getAccessType()); - } - - @Test - @SuppressWarnings("checkstyle:methodLength") - public void shouldUpdateAllAttributesInCustomPackageAndUpdateAccessTypeMapping() - throws URISyntaxException, IOException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - final String currentAccessTypeId = accessTypes.get(0).getId(); - final String newAccessTypeId = accessTypes.get(1).getId(); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, currentAccessTypeId, vertx); - - boolean updatedSelected = true; - boolean updatedHidden = true; - String updatedBeginCoverage = "2003-01-01"; - String updatedEndCoverage = "2004-01-01"; - String updatedPackageName = "name of the ages forever and ever"; - - var updatedPackageValue = prepareCustomPackageData(updatedSelected, updatedHidden, updatedBeginCoverage, - updatedEndCoverage, updatedPackageName); - mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE), updatedPackageValue); - - String putBody = format(readFile("requests/kb-ebsco/package/put-package-custom-with-access-type.json"), - newAccessTypeId); - Package actualPackage = putWithOk(PACKAGES_PATH, putBody, STUB_USER_ID_HEADER).as(Package.class); - - verify(putRequestedFor(PACKAGE_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), true, true))); - - assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); - assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); - assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); - assertEquals(updatedPackageName, actualPackage.getData().getAttributes().getName()); - assertEquals(ContentType.STREAMING_MEDIA, actualPackage.getData().getAttributes().getContentType()); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(1, accessTypeMappingsInDb.size()); - assertEquals(actualPackage.getData().getId(), accessTypeMappingsInDb.getFirst().getRecordId()); - assertEqualsUuid(newAccessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); - assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); - assertNotNull(actualPackage.getIncluded()); - assertEquals(newAccessTypeId, actualPackage.getData().getRelationships().getAccessType().getData().getId()); - assertEquals(newAccessTypeId, ((LinkedHashMap<?, ?>) actualPackage.getIncluded().getFirst()).get("id")); - } - - @Test - public void shouldReturn400OnPutPackageWithNotExistedAccessType() throws URISyntaxException, IOException { - String requestBody = readFile("requests/kb-ebsco/package/put-package-with-not-existed-access-type.json"); - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); - - JsonapiError error = - putWithStatus(PACKAGES_PATH, requestBody, SC_BAD_REQUEST, CONTENT_TYPE_HEADER, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Access type not found: id = 99999999-9999-1999-a999-999999999999"); - } - - @Test - public void shouldReturn422OnPutPackageWithInvalidAccessTypeId() throws URISyntaxException, IOException { - String requestBody = readFile("requests/kb-ebsco/package/put-package-with-invalid-access-type.json"); - - Errors error = - putWithStatus(PACKAGES_PATH, requestBody, SC_UNPROCESSABLE_ENTITY, CONTENT_TYPE_HEADER, STUB_USER_ID_HEADER) - .as(Errors.class); - - assertEquals(1, error.getErrors().size()); - assertEquals( - "must match \"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[1-5][a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$\"", - error.getErrors().getFirst().getMessage()); - } - - @Test - public void shouldReturn400WhenRmApiReturns400() throws URISyntaxException, IOException { - EqualToPattern urlPattern = new EqualToPattern(PACKAGE_BY_ID_URL); - - mockGet(urlPattern, PACKAGE_STUB_FILE); - mockPut(urlPattern, SC_BAD_REQUEST); - - JsonapiError error = - putWithStatus(PACKAGES_PATH, readFile("requests/kb-ebsco/package/put-package-selected.json"), SC_BAD_REQUEST, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertEquals(1, error.getErrors().size()); - } - - @Test - public void shouldReturn200WhenPackagePostIsValid() throws URISyntaxException, IOException { - String packagePostStubRequestFile = "requests/kb-ebsco/package/post-package-request.json"; - String packagePostRmApiRequestFile = "requests/rmapi/packages/post-package.json"; - - final Package createdPackage = sendPost(readFile(packagePostStubRequestFile)).as(Package.class); - - assertTrue(Objects.isNull(createdPackage.getData().getAttributes().getTags())); - verify(1, postRequestedFor(new UrlPathPattern(new EqualToPattern(PACKAGES_STUB_URL), false)) - .withRequestBody(equalToJson(readFile(packagePostRmApiRequestFile), false, true))); - } - - @Test - public void shouldReturn200OnPostPackageWithExistedAccessType() throws URISyntaxException, IOException { - String accessTypeId = insertAccessType(testData(configuration.getId()).getFirst(), vertx); - - String packagePostRmApiRequestFile = "requests/rmapi/packages/post-package.json"; - String requestBody = format(readFile("requests/kb-ebsco/package/post-package-with-access-type-request.json"), - accessTypeId); - Package createdPackage = sendPost(requestBody).as(Package.class); - - assertTrue(Objects.isNull(createdPackage.getData().getAttributes().getTags())); - verify(1, postRequestedFor(new UrlPathPattern(new EqualToPattern(PACKAGES_STUB_URL), false)) - .withRequestBody(equalToJson(readFile(packagePostRmApiRequestFile), false, true))); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(1, accessTypeMappingsInDb.size()); - assertEqualsUuid(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId()); - assertEquals(PACKAGE, accessTypeMappingsInDb.getFirst().getRecordType()); - assertNotNull(createdPackage.getIncluded()); - assertEquals(accessTypeId, createdPackage.getData().getRelationships().getAccessType().getData().getId()); - assertEquals(accessTypeId, ((LinkedHashMap<?, ?>) createdPackage.getIncluded().getFirst()).get("id")); - } - - @Test - public void shouldReturn400OnPostPackageWithNotExistedAccessType() throws URISyntaxException, IOException { - String requestBody = readFile("requests/kb-ebsco/package/post-package-with-not-existed-access-type-request.json"); - mockUpdateScenario(readFile(CUSTOM_PACKAGE_STUB_FILE)); - - JsonapiError error = postWithStatus(PACKAGES_ENDPOINT, requestBody, SC_BAD_REQUEST, CONTENT_TYPE_HEADER, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Access type not found: id = 99999999-9999-1999-a999-999999999999"); - } - - @Test - public void shouldReturn422OnPostPackageWithInvalidAccessTypeId() throws URISyntaxException, IOException { - String requestBody = readFile("requests/kb-ebsco/package/post-package-with-invalid-access-type-request.json"); - - Errors error = postWithStatus(PACKAGES_ENDPOINT, requestBody, SC_UNPROCESSABLE_ENTITY, CONTENT_TYPE_HEADER, - STUB_USER_ID_HEADER).as(Errors.class); - - assertEquals(1, error.getErrors().size()); - assertEquals( - "must match \"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[1-5][a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$\"", - error.getErrors().getFirst().getMessage()); - } - - @Test - public void shouldReturn400WhenPackagePostDataIsInvalid() throws URISyntaxException, IOException { - String providerStubResponseFile = "responses/rmapi/packages/get-package-provider-by-id.json"; - String packagePostStubRequestFile = "requests/kb-ebsco/package/post-package-request.json"; - String response = "responses/rmapi/packages/post-package-400-error-response.json"; - - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors.*"), providerStubResponseFile); - mockPost(new EqualToPattern(PACKAGES_STUB_URL), - equalToJson(""" - { - "contentType" : 1, - "packageName" : "TEST_NAME", - "customCoverage" : { - "beginCoverage" : "2017-12-23", - "endCoverage" : "2018-03-30" - } - }""", - false, true), response, SC_BAD_REQUEST); - - RestAssured.given() - .spec(getRequestSpecification()) - .header(STUB_USER_ID_HEADER) - .body(readFile(packagePostStubRequestFile)) - .when() - .post(PACKAGES_ENDPOINT) - .then() - .statusCode(SC_BAD_REQUEST); - } - - @Test - public void shouldReturnDefaultResourcesOnGetWithResources() throws IOException, URISyntaxException, JSONException { - String query = "?searchfield=titlename&selection=all&resourcetype=all" - + "&searchtype=advanced&search=&offset=1&count=25&orderby=titlename"; - shouldReturnResourcesOnGetWithResources(PACKAGE_RESOURCES_PATH, query); - } - - @Test - public void shouldReturnResourcesWithPagingOnGetWithResources() - throws IOException, URISyntaxException, JSONException { - String packageResourcesUrl = PACKAGE_RESOURCES_PATH + "?page=2"; - String query = "?searchfield=titlename&selection=all&resourcetype=all" - + "&searchtype=advanced&search=&offset=2&count=25&orderby=titlename"; - shouldReturnResourcesOnGetWithResources(packageResourcesUrl, query); - } - - @Test - public void shouldReturnEmptyListWhenResourcesAreNotFound() throws IOException, URISyntaxException { - mockResourceById(RESOURCES_BY_PACKAGE_ID_EMPTY_STUB_FILE); - - ResourceCollection actual = getWithOk(PACKAGE_RESOURCES_PATH, STUB_USER_ID_HEADER).as(ResourceCollection.class); - assertThat(actual.getData(), empty()); - assertEquals(0, (int) actual.getMeta().getTotalResults()); - } - - @Test - public void shouldReturnResourcesWithTagsOnGetWithResources() throws IOException, URISyntaxException, JSONException { - saveTag(vertx, "295-2545963-2099944", RESOURCE, STUB_TAG_VALUE); - saveTag(vertx, "295-2545963-2172685", RESOURCE, STUB_TAG_VALUE_2); - saveTag(vertx, "295-2545963-2172685", RESOURCE, STUB_TAG_VALUE_3); - - String query = "?searchfield=titlename&selection=all&resourcetype=all&searchtype=advanced" - + "&search=&offset=1&count=25&orderby=titlename"; - - mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); - - String actual = getWithOk(PACKAGE_RESOURCES_PATH, STUB_USER_ID_HEADER).asString(); - String expected = readFile(EXPECTED_RESOURCES_WITH_TAGS_STUB_FILE); - - JSONAssert.assertEquals(expected, actual, false); - - verify(1, getRequestedFor(urlEqualTo(RESOURCES_BY_PACKAGE_ID_URL + query))); - } - - @Test - public void shouldReturnResourcesWithAccessTypesOnGetWithResources() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.getFirst().getId(), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.getFirst().getId(), vertx); - - mockResourceById("responses/rmapi/titles/get-title-by-id-response.json"); - - String resourcePath = PACKAGES_ENDPOINT + "/" + FULL_PACKAGE_ID + "/resources" - + "?filter[access-type]=" + STUB_ACCESS_TYPE_NAME; - ResourceCollection resourceCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(ResourceCollection.class); - List<ResourceCollectionItem> resources = resourceCollection.getData(); - - assertEquals(2, (int) resourceCollection.getMeta().getTotalResults()); - assertEquals(2, resources.size()); - assertThat(resources, everyItem(hasProperty("id", - anyOf(equalTo(STUB_MANAGED_RESOURCE_ID), equalTo(STUB_MANAGED_RESOURCE_ID_2)) - ))); - } - - @Test - public void shouldReturnResourcesWithAccessTypesOnGetWithResourcesWithPagination() - throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.get(0).getId(), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.get(1).getId(), vertx); - - mockResourceById("responses/rmapi/titles/get-title-by-id-response.json"); - - String resourcePath = PACKAGES_ENDPOINT + "/" + FULL_PACKAGE_ID + "/resources?page=2&count=1&" - + "filter[access-type]=" + STUB_ACCESS_TYPE_NAME + "&filter[access-type]=" - + STUB_ACCESS_TYPE_NAME_2; - ResourceCollection resourceCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(ResourceCollection.class); - List<ResourceCollectionItem> resources = resourceCollection.getData(); - - assertEquals(2, (int) resourceCollection.getMeta().getTotalResults()); - assertEquals(1, resources.size()); - assertThat(resources, everyItem(hasProperty("id", equalTo(STUB_MANAGED_RESOURCE_ID)))); - } - - @Test - public void shouldReturnResourcesWithAccessTypesOnGetWithResources1() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping("295-2545963-2099944", RESOURCE, accessTypes.get(0).getId(), vertx); - insertAccessTypeMapping("295-2545963-2172685", RESOURCE, accessTypes.get(1).getId(), vertx); - - mockResourceById("responses/rmapi/titles/get-title-by-id-response.json"); - mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); - - ResourceCollection resourceCollection = - getWithOk(PACKAGE_RESOURCES_PATH, STUB_USER_ID_HEADER).as(ResourceCollection.class); - List<ResourceCollectionItem> resources = resourceCollection.getData(); - - assertEquals(5, (int) resourceCollection.getMeta().getTotalResults()); - assertEquals(5, resources.size()); - - assertEquals("295-2545963-2099944", resources.getFirst().getId()); - assertEquals(1, resources.get(0).getIncluded().size()); - assertEquals(accessTypes.getFirst().getId(), - ((LinkedHashMap<?, ?>) resources.get(0).getIncluded().getFirst()).get("id")); - assertEquals("295-2545963-2172685", resources.get(2).getId()); - assertEquals(1, resources.get(2).getIncluded().size()); - assertEquals(accessTypes.get(1).getId(), - ((LinkedHashMap<?, ?>) resources.get(2).getIncluded().getFirst()).get("id")); - } - - @Test - public void shouldReturnFilteredResourcesWithNonEmptyCustomerResourceList() throws IOException, URISyntaxException { - mockResourceById(RESOURCES_BY_PACKAGE_ID_EMPTY_CUSTOMER_RESOURCE_LIST_STUB_FILE); - final ResourceCollection resourceCollection = getWithOk(PACKAGE_RESOURCES_PATH, STUB_USER_ID_HEADER) - .as(ResourceCollection.class); - - final MetaTotalResults metaTotalResults = resourceCollection.getMeta(); - assertThat(metaTotalResults.getTotalResults(), equalTo(3)); - } - - @Test - public void shouldReturnResourcesWithOnSearchByTags() throws IOException, URISyntaxException, JSONException { - mockResourceById("responses/rmapi/resources/get-resource-by-id-success-response.json"); - - ResourcesTestUtil.saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, configuration.getId(), STUB_TITLE_NAME), - vertx); - - saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RESOURCE, STUB_TAG_VALUE); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RESOURCE, STUB_TAG_VALUE_2); - - String packageResourcesUrl = PACKAGE_RESOURCES_PATH + "?filter[tags]=" + STUB_TAG_VALUE; - - String actualResponse = getWithOk(packageResourcesUrl, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile("responses/kb-ebsco/resources/expected-tagged-resources.json"), actualResponse, - false); - } - - @Test - public void shouldReturn404OnGetWithResourcesWhenPackageNotFound() { - mockGet(new RegexPattern(RESOURCES_BY_PACKAGE_ID_URL + ".*"), SC_NOT_FOUND); - - JsonapiError error = - getWithStatus(PACKAGE_RESOURCES_PATH, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Package not found"); - } - - @Test - public void shouldReturn400OnGetWithResourcesWhenCountOutOfRange() { - String packageResourcesUrl = PACKAGE_RESOURCES_PATH + "?count=500"; - - JsonapiError error = getWithStatus(packageResourcesUrl, SC_BAD_REQUEST, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "is not valid"); - } - - @Test - public void shouldReturn400OnGetWithResourcesWhenRmApi400() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/packages/get-package-resources-400-response.json"; - - stubFor( - get( - new UrlPathPattern(new RegexPattern( - PACKAGE_BY_ID_URL + "/titles.*"), - true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)) - .withStatus(SC_BAD_REQUEST))); - - JsonapiError error = - getWithStatus(PACKAGE_RESOURCES_PATH, SC_BAD_REQUEST, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Parameter Count is outside the range 1-100."); - } - - @Test - public void shouldReturnUnauthorizedOnGetWithResourcesWhenRmApi401() { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL + "/titles.*"), HttpStatus.SC_UNAUTHORIZED); - - JsonapiError error = - getWithStatus(PACKAGE_RESOURCES_PATH, SC_FORBIDDEN, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturnUnauthorizedOnGetWithResourcesWhenRmApi403() { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL + "/titles.*"), SC_FORBIDDEN); - - JsonapiError error = - getWithStatus(PACKAGE_RESOURCES_PATH, SC_FORBIDDEN, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldFetchPackagesInBulk() throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), PACKAGE_STUB_FILE); - mockGet(new RegexPattern(PACKAGE_BY_ID_2_URL), PACKAGE_2_STUB_FILE); - - String postBody = readFile("requests/kb-ebsco/package/post-packages-bulk.json"); - final String actualResponse = postWithOk(PACKAGES_BULK_FETCH_PATH, postBody, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile("responses/kb-ebsco/packages/expected-post-packages-bulk.json"), - actualResponse, false); - } - - @Test - public void shouldReturn422OnFetchPackagesInBulkWithInvalidIdFormat() throws IOException, URISyntaxException { - String postBody = readFile("requests/kb-ebsco/package/post-packages-bulk-with-invalid-id-format.json"); - - Errors error = postWithStatus(PACKAGES_BULK_FETCH_PATH, postBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(Errors.class); - - assertThat(error.getErrors().getFirst().getMessage(), equalTo("elements in list must match pattern")); - } - - @Test - public void shouldReturnPackagesAndFailedIdsOnFetchPackagesInBulk() - throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), PACKAGE_STUB_FILE); - mockGet(new RegexPattern(PACKAGE_BY_ID_2_URL), PACKAGE_2_STUB_FILE); - - String notFoundResponse = "responses/rmapi/packages/get-package-by-id-not-found-response.json"; - stubFor( - get(new UrlPathPattern(new EqualToPattern(PACKAGES_STUB_URL + "/9999999"), false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(notFoundResponse)) - .withStatus(404))); - - String postBody = readFile("requests/kb-ebsco/package/post-packages-bulk-with-non-existing-id.json"); - final String actualResponse = postWithOk(PACKAGES_BULK_FETCH_PATH, postBody, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile("responses/kb-ebsco/packages/expected-post-packages-bulk-with-failed-id.json"), - actualResponse, false); - } - - @Test - public void shouldReturnEmptyPackagesOnFetchPackagesInBulkIfNoPackageIds() - throws IOException, URISyntaxException, JSONException { - String postBody = readFile("requests/kb-ebsco/package/post-packages-bulk-empty.json"); - final String actualResponse = postWithOk(PACKAGES_BULK_FETCH_PATH, postBody, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile("responses/kb-ebsco/packages/expected-post-packages-bulk-empty.json"), - actualResponse, false); - } - - private String prepareCustomPackageData(boolean updatedSelected, boolean updatedHidden, String updatedBeginCoverage, - String updatedEndCoverage, String updatedPackageName) - throws IOException, URISyntaxException { - PackageByIdData packageData = mapper.readValue(getFile(CUSTOM_PACKAGE_STUB_FILE), PackageByIdData.class); - - packageData = packageData.toByIdBuilder() - .isSelected(updatedSelected) - .visibilityData(packageData.getVisibilityData().toBuilder().isHidden(updatedHidden).build()) - .customCoverage(CoverageDates.builder() - .beginCoverage(updatedBeginCoverage) - .endCoverage(updatedEndCoverage) - .build()) - .packageName(updatedPackageName) - .contentType("streamingmedia") - .build(); - - return mapper.writeValueAsString(packageData); - } - - private String preparePackageData(boolean updatedSelected, String updatedBeginCoverage, String updatedEndCoverage, - boolean updatedAllowEbscoToAddTitles, boolean updatedHidden) - throws IOException, URISyntaxException { - PackageByIdData packageData = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageByIdData.class); - - packageData = packageData.toByIdBuilder() - .isSelected(updatedSelected) - .customCoverage(CoverageDates.builder() - .beginCoverage(updatedBeginCoverage) - .endCoverage(updatedEndCoverage) - .build()) - .allowEbscoToAddTitles(updatedAllowEbscoToAddTitles) - .visibilityData(packageData.getVisibilityData().toBuilder().isHidden(updatedHidden).build()) - .build(); - - return mapper.writeValueAsString(packageData); - } - - private void shouldReturnResourcesOnGetWithResources(String getUrl, String rmApiQuery) - throws IOException, URISyntaxException, JSONException { - mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); - - String actual = getWithOk(getUrl, STUB_USER_ID_HEADER).asString(); - String expected = readFile(EXPECTED_RESOURCES_STUB_FILE); - - JSONAssert.assertEquals(expected, actual, false); - - verify(1, getRequestedFor(urlEqualTo(RESOURCES_BY_PACKAGE_ID_URL + rmApiQuery))); - } - - private void mockResourceById(String stubFile) throws IOException, URISyntaxException { - mockGet(new RegexPattern(RESOURCES_BY_PACKAGE_ID_URL + ".*"), stubFile); - } - - private void mockUpdateScenario(String initialPackage, String updatedPackage) { - mockUpdateScenario(initialPackage); - - stubFor( - get(PACKAGE_URL_PATTERN) - .inScenario(GET_PACKAGE_SCENARIO) - .whenScenarioStateIs(PACKAGE_UPDATED_STATE) - .willReturn(new ResponseDefinitionBuilder() - .withBody(updatedPackage))); - } - - private void mockUpdateScenario(String initialPackage) { - stubFor( - get(PACKAGE_URL_PATTERN) - .inScenario(GET_PACKAGE_SCENARIO) - .willReturn(new ResponseDefinitionBuilder() - .withBody(initialPackage))); - - stubFor( - put(PACKAGE_URL_PATTERN) - .inScenario(GET_PACKAGE_SCENARIO) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(SC_NO_CONTENT)) - .willSetStateTo(PACKAGE_UPDATED_STATE)); - } - - private Package sendPut(String mockUpdatedPackage) throws IOException, URISyntaxException { - mockUpdateScenario(readFile(PACKAGE_STUB_FILE), mockUpdatedPackage); - - PackagePutRequest packageToBeUpdated = - mapper.readValue(getFile("requests/kb-ebsco/package/put-package-selected.json"), PackagePutRequest.class); - - return putWithOk(PACKAGES_PATH, mapper.writeValueAsString(packageToBeUpdated), STUB_USER_ID_HEADER).as( - Package.class); - } - - private void sendPutTags(List<String> newTags) throws IOException, URISyntaxException { - PackageTagsPutRequest tags = - mapper.readValue(getFile("requests/kb-ebsco/package/put-package-tags.json"), PackageTagsPutRequest.class); - - if (newTags != null) { - tags.getData().getAttributes().setTags(new Tags() - .withTagList(newTags)); - } - - putWithOk(PACKAGE_TAGS_PATH, mapper.writeValueAsString(tags), STUB_USER_ID_HEADER).as(PackageTags.class); - } - - private ExtractableResponse<Response> sendPost(String requestBody) throws IOException, URISyntaxException { - String providerStubResponseFile = "responses/rmapi/packages/get-package-provider-by-id.json"; - String packageCreatedIdStubResponseFile = "responses/rmapi/packages/post-package-response.json"; - - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/"), providerStubResponseFile); - mockPost(new EqualToPattern(PACKAGES_STUB_URL), new AnythingPattern(), packageCreatedIdStubResponseFile, SC_OK); - mockGet(new EqualToPattern(PACKAGE_BY_ID_URL), PACKAGE_STUB_FILE); - - PackagePostRequest request = mapper.readValue(requestBody, PackagePostRequest.class); - return postWithOk(PACKAGES_ENDPOINT, mapper.writeValueAsString(request), STUB_USER_ID_HEADER); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java deleted file mode 100644 index f471488f9..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java +++ /dev/null @@ -1,600 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.ok; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.apache.commons.lang3.RandomStringUtils.insecure; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.RecordType.PACKAGE; -import static org.folio.repository.RecordType.PROVIDER; -import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; -import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.repository.packages.PackageTableConstants.PACKAGES_TABLE_NAME; -import static org.folio.repository.providers.ProviderTableConstants.PROVIDERS_TABLE_NAME; -import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID_2; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID_3; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID_4; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID_5; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID_2; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID_3; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME_2; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME_3; -import static org.folio.rest.impl.ProvidersTestData.PROVIDER_TAGS_PATH; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID_2; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID_3; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_NAME; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_NAME_2; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_NAME_3; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE_2; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE_3; -import static org.folio.rest.util.RestConstants.PROVIDERS_TYPE; -import static org.folio.test.util.TestUtil.getFile; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.mockGetWithBody; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.test.util.TestUtil.readJsonFile; -import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME; -import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME_2; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; -import static org.folio.util.AccessTypesTestUtil.testData; -import static org.folio.util.AssertTestUtil.assertErrorContainsDetail; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.getDefaultKbConfiguration; -import static org.folio.util.KbTestUtil.setupDefaultKbConfiguration; -import static org.folio.util.PackagesTestUtil.setUpPackage; -import static org.folio.util.ProvidersTestUtil.buildDbProvider; -import static org.folio.util.TagsTestUtil.saveTag; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.List; -import org.folio.holdingsiq.model.VendorById; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.AccessType; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.KbCredentials; -import org.folio.rest.jaxrs.model.PackageCollection; -import org.folio.rest.jaxrs.model.PackageCollectionItem; -import org.folio.rest.jaxrs.model.PackageTags; -import org.folio.rest.jaxrs.model.PackageTagsPutRequest; -import org.folio.rest.jaxrs.model.Provider; -import org.folio.rest.jaxrs.model.ProviderCollection; -import org.folio.rest.jaxrs.model.ProviderPutRequest; -import org.folio.rest.jaxrs.model.ProviderTagsPutRequest; -import org.folio.rest.jaxrs.model.Providers; -import org.folio.rest.jaxrs.model.Tags; -import org.folio.rest.jaxrs.model.Token; -import org.folio.util.PackagesTestUtil; -import org.folio.util.ProvidersTestUtil; -import org.folio.util.TagsTestUtil; -import org.json.JSONException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.skyscreamer.jsonassert.JSONAssert; -import org.skyscreamer.jsonassert.JSONCompareMode; - -@RunWith(VertxUnitRunner.class) -public class EholdingsProvidersImplTest extends WireMockTestBase { - - private static final String PROVIDER_RM_API_PATH = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors.*"; - private static final String PROVIDER_PACKAGES_RM_API_PATH = - "/rm/rmaccounts.*" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages.*"; - private static final UrlPathPattern PROVIDER_URL_PATTERN = - new UrlPathPattern(new RegexPattern(PROVIDER_RM_API_PATH), true); - - private static final String PROVIDER_PATH = "eholdings/providers"; - private static final String PROVIDER_BY_ID = PROVIDER_PATH + "/" + STUB_VENDOR_ID; - private static final String PROVIDER_PACKAGES = PROVIDER_BY_ID + "/packages"; - - private static final String PUT_PROVIDER = "requests/kb-ebsco/provider/put-provider.json"; - private static final String PUT_PROVIDER_TAGS = "requests/kb-ebsco/provider/put-provider-tags.json"; - private static final String STUB_PACKAGE_RESPONSE = "responses/rmapi/packages/get-packages-by-provider-id.json"; - - private KbCredentials configuration; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - configuration = getDefaultKbConfiguration(vertx); - } - - @After - public void tearDown() { - clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); - clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); - clearDataFromTable(vertx, TAGS_TABLE_NAME); - clearDataFromTable(vertx, PROVIDERS_TABLE_NAME); - clearDataFromTable(vertx, PACKAGES_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnProvidersOnGet() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/vendors/get-vendors-response.json"; - stubFor(get(PROVIDER_URL_PATTERN).willReturn(ok(readFile(stubResponseFile)))); - - RestAssured.given() - .spec(getRequestSpecification()) - .header(STUB_USER_ID_HEADER) - .when() - .get(PROVIDER_PATH + "?q=e&page=1&sort=name") - .then() - .statusCode(SC_OK) - .body("meta.totalResults", equalTo(115)) - .body("data[0].type", equalTo(PROVIDERS_TYPE)) - .body("data[0].id", equalTo("131872")) - .body("data[0].attributes.name", equalTo("Editions de L'Universite de Bruxelles")) - .body("data[0].attributes.packagesTotal", equalTo(1)) - .body("data[0].attributes.packagesSelected", equalTo(0)) - .body("data[0].attributes.supportsCustomPackages", equalTo(false)) - .body("data[0].attributes.providerToken.value", equalTo("sampleToken")); - } - - @Test - public void shouldReturnProvidersOnSearchByTagsOnly() { - saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); - saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE); - saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE_2); - saveTag(vertx, STUB_VENDOR_ID_3, PROVIDER, STUB_TAG_VALUE_3); - - setUpTaggedProviders(); - - ProviderCollection providerCollection = - getWithOk(PROVIDER_PATH + "?filter[tags]=" + STUB_TAG_VALUE + "&filter[tags]=" + STUB_TAG_VALUE_2, - STUB_USER_ID_HEADER) - .as(ProviderCollection.class); - - List<Providers> providers = providerCollection.getData(); - - assertEquals(2, (int) providerCollection.getMeta().getTotalResults()); - assertEquals(2, providers.size()); - assertEquals(STUB_VENDOR_NAME, providers.get(0).getAttributes().getName()); - assertEquals(STUB_VENDOR_NAME_2, providers.get(1).getAttributes().getName()); - } - - @Test - public void shouldReturnPackagesOnSearchByProviderIdAndTagsOnly() throws IOException, URISyntaxException { - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE_2); - saveTag(vertx, FULL_PACKAGE_ID_2, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_3, PACKAGE, STUB_TAG_VALUE_2); - - PackagesTestUtil.setUpPackages(vertx, configuration.getId()); - - String endpoint = PROVIDER_PACKAGES + "?filter[tags]=" + STUB_TAG_VALUE; - PackageCollection packageCollection = getWithOk(endpoint, STUB_USER_ID_HEADER).as(PackageCollection.class); - - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(1, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(1, packages.size()); - assertThat(packages.getFirst().getAttributes().getTags().getTagList(), containsInAnyOrder(STUB_TAG_VALUE, - STUB_TAG_VALUE_2)); - assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getAttributes().getName()); - } - - @Test - public void shouldReturnPackagesOnSearchByProviderIdAndTagsWithPagination() throws IOException, URISyntaxException { - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_4, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID_5, PACKAGE, STUB_TAG_VALUE_2); - - String credentialsId = configuration.getId(); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_2, STUB_VENDOR_ID, STUB_PACKAGE_NAME_2); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_3, STUB_VENDOR_ID, STUB_PACKAGE_NAME_3); - - PackageCollection packageCollection = getWithOk(PROVIDER_PACKAGES + "?page=2&count=1&filter[tags]=" + STUB_TAG_VALUE - + "&filter[tags]=" + STUB_TAG_VALUE_2, STUB_USER_ID_HEADER).as( - PackageCollection.class); - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(3, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(1, packages.size()); - assertEquals(STUB_PACKAGE_NAME_2, packages.getFirst().getAttributes().getName()); - } - - @Test - public void shouldReturnPackagesOnSearchByProviderIdAndAccessTypeWithPagination() - throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.get(0).getId(), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID_4, PACKAGE, accessTypes.get(1).getId(), vertx); - - String credentialsId = configuration.getId(); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_2, STUB_VENDOR_ID, STUB_PACKAGE_NAME_2); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_3, STUB_VENDOR_ID, STUB_PACKAGE_NAME_3); - - String resourcePath = PROVIDER_PACKAGES + "?page=2&count=1&filter[access-type]=" + STUB_ACCESS_TYPE_NAME - + "&filter[access-type]=" + STUB_ACCESS_TYPE_NAME_2; - PackageCollection packageCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(PackageCollection.class); - - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(1, packages.size()); - assertEquals(STUB_PACKAGE_NAME, packages.getFirst().getAttributes().getName()); - } - - @Test - public void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByAccessType() { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, accessTypes.getFirst().getId(), vertx); - insertAccessTypeMapping(FULL_PACKAGE_ID_4, PACKAGE, accessTypes.getFirst().getId(), vertx); - - mockGet(new RegexPattern(".*vendors/.*/packages/.*"), SC_INTERNAL_SERVER_ERROR); - - String resourcePath = PROVIDER_PACKAGES + "?filter[access-type]=" + STUB_ACCESS_TYPE_NAME; - PackageCollection packageCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(PackageCollection.class); - List<PackageCollectionItem> packages = packageCollection.getData(); - - assertEquals(2, (int) packageCollection.getMeta().getTotalResults()); - assertEquals(0, packages.size()); - } - - @Test - public void shouldReturnEmptyResponseWhenProvidersReturnedWithErrorOnSearchByTags() { - String credentialsId = configuration.getId(); - ProvidersTestUtil.saveProvider(buildDbProvider(STUB_VENDOR_ID, credentialsId, STUB_VENDOR_NAME), vertx); - ProvidersTestUtil.saveProvider(buildDbProvider(STUB_VENDOR_ID_2, credentialsId, STUB_VENDOR_NAME_2), vertx); - - saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); - saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE); - - mockGet(new RegexPattern(".*vendors/.*"), SC_INTERNAL_SERVER_ERROR); - - ProviderCollection providerCollection = getWithOk(PROVIDER_PATH + "?filter[tags]=" + STUB_TAG_VALUE, - STUB_USER_ID_HEADER).as(ProviderCollection.class); - List<Providers> providers = providerCollection.getData(); - - assertEquals(2, (int) providerCollection.getMeta().getTotalResults()); - assertEquals(0, providers.size()); - } - - @Test - public void shouldReturnProvidersOnSearchWithTagsAndPagination() { - saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); - saveTag(vertx, STUB_VENDOR_ID_2, PROVIDER, STUB_TAG_VALUE); - saveTag(vertx, STUB_VENDOR_ID_3, PROVIDER, STUB_TAG_VALUE); - - setUpTaggedProviders(); - - ProviderCollection providerCollection = getWithOk(PROVIDER_PATH + "?page=2&count=1&filter[tags]=" + STUB_TAG_VALUE, - STUB_USER_ID_HEADER).as(ProviderCollection.class); - List<Providers> providers = providerCollection.getData(); - - assertEquals(3, (int) providerCollection.getMeta().getTotalResults()); - assertEquals(1, providers.size()); - assertEquals(STUB_VENDOR_NAME_2, providers.getFirst().getAttributes().getName()); - } - - @Test - public void shouldReturnProvidersOnGetWithPackages() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/vendors/get-vendor-by-id-response.json"; - String expectedProviderFile = "responses/kb-ebsco/providers/expected-provider-with-packages.json"; - - stubFor( - get(PROVIDER_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)))); - - stubFor( - get(new UrlPathPattern( - new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(STUB_PACKAGE_RESPONSE)))); - - String actualProvider = getWithOk(PROVIDER_BY_ID + "?include=packages", STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedProviderFile), actualProvider, false); - } - - @Test - public void shouldReturn500IfRmApiReturnsError() { - stubFor( - get(PROVIDER_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(SC_INTERNAL_SERVER_ERROR))); - - final JsonapiError error = getWithStatus(PROVIDER_PATH + "?q=e&count=1", SC_INTERNAL_SERVER_ERROR, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertThat(error.getErrors().getFirst().getTitle(), notNullValue()); - } - - @Test - public void shouldReturnErrorIfSortParameterInvalid() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "?q=e&count=10&sort=abc"); - } - - @Test - public void shouldReturnProviderWhenValidId() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/vendors/get-vendor-by-id-response.json"; - String expectedProviderFile = "responses/kb-ebsco/providers/expected-provider.json"; - - stubFor( - get(PROVIDER_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)))); - - String provider = getWithOk(PROVIDER_BY_ID, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedProviderFile), provider, false); - } - - @Test - public void shouldReturnProviderWithTagWhenValidId() throws IOException, URISyntaxException { - saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); - - String stubResponseFile = "responses/rmapi/vendors/get-vendor-by-id-response.json"; - - stubFor(get(PROVIDER_URL_PATTERN).willReturn(new ResponseDefinitionBuilder().withBody(readFile(stubResponseFile)))); - - Provider provider = getWithOk(PROVIDER_BY_ID, STUB_USER_ID_HEADER).as(Provider.class); - - assertTrue(provider.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); - } - - @Test - public void shouldReturn404WhenProviderIdNotFound() { - stubFor( - get(PROVIDER_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(SC_NOT_FOUND))); - - JsonapiError error = - getWithStatus(PROVIDER_PATH + "/191919", SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Provider not found"); - } - - @Test - public void shouldReturn400WhenInvalidProviderId() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/19191919as"); - } - - @Test - public void shouldUpdateAndReturnProvider() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/vendors/get-vendor-updated-response.json"; - String expectedProviderFile = "responses/kb-ebsco/providers/expected-updated-provider.json"; - - stubFor( - get(PROVIDER_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder().withBody(readFile(stubResponseFile)))); - - stubFor( - put(PROVIDER_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder().withStatus(SC_NO_CONTENT))); - - String provider = putWithOk(PROVIDER_BY_ID, readFile(PUT_PROVIDER), STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedProviderFile), provider, false); - - verify(1, - putRequestedFor(PROVIDER_URL_PATTERN) - .withRequestBody(equalToJson(readFile("requests/rmapi/vendors/put-vendor-token-proxy.json")))); - } - - @Test - public void shouldUpdateTagsOnPutTags() throws IOException, URISyntaxException { - List<String> newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); - sendPutTags(Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); - List<String> tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PROVIDER); - assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); - } - - @Test - public void shouldUpdateTagsOnPutTagsWithAlreadyExistingTags() throws IOException, URISyntaxException { - saveTag(vertx, STUB_VENDOR_ID, PROVIDER, STUB_TAG_VALUE); - List<String> newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); - sendPutTags(Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); - List<String> tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, PROVIDER); - assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); - } - - @Test - public void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - PackageTagsPutRequest tags = mapper.readValue(getFile(PUT_PROVIDER_TAGS), - PackageTagsPutRequest.class); - tags.getData().getAttributes().setName(""); - JsonapiError error = putWithStatus(PROVIDER_TAGS_PATH, mapper.writeValueAsString(tags), - SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - assertErrorContainsDetail(error, "name must not be empty"); - } - - @Test - public void shouldReturn400WhenRmApiErrorOnPut() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/vendors/put-vendor-token-not-allowed-response.json"; - - stubFor( - put(PROVIDER_URL_PATTERN) - .willReturn(new ResponseDefinitionBuilder().withBody(readFile(stubResponseFile)).withStatus(SC_BAD_REQUEST))); - - JsonapiError error = putWithStatus(PROVIDER_BY_ID, readFile(PUT_PROVIDER), SC_BAD_REQUEST, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Provider does not allow token"); - } - - @Test - public void shouldReturn422WhenBodyInputInvalidOnPut() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - ProviderPutRequest providerToBeUpdated = mapper.readValue(getFile(PUT_PROVIDER), ProviderPutRequest.class); - - Token providerToken = new Token(); - providerToken.setValue(insecure().nextAlphanumeric(501)); - - providerToBeUpdated.getData().getAttributes().setProviderToken(providerToken); - - JsonapiError error = putWithStatus(PROVIDER_BY_ID, mapper.writeValueAsString(providerToBeUpdated), - SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid value"); - assertErrorContainsDetail(error, "Value is too long (maximum is 500 characters)"); - } - - @Test - public void shouldReturnProviderPackagesWhenValidId() throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PROVIDER_PACKAGES_RM_API_PATH), STUB_PACKAGE_RESPONSE); - - String actual = getWithOk(PROVIDER_PACKAGES, STUB_USER_ID_HEADER).asString(); - String expected = readFile("responses/kb-ebsco/packages/expected-package-collection-with-one-element.json"); - - JSONAssert.assertEquals(expected, actual, false); - } - - @Test - public void shouldReturnEmptyPackageListWhenNoProviderPackagesAreFound() throws IOException, URISyntaxException { - String packageStubResponseFile = "responses/rmapi/packages/get-packages-by-provider-id-empty.json"; - - mockGet(new RegexPattern(PROVIDER_PACKAGES_RM_API_PATH), packageStubResponseFile); - - PackageCollection packages = getWithOk(PROVIDER_PACKAGES, STUB_USER_ID_HEADER).as(PackageCollection.class); - assertThat(packages.getData(), empty()); - assertEquals(0, (int) packages.getMeta().getTotalResults()); - } - - @Test - public void shouldReturnProviderPackagesWithTags() throws IOException, URISyntaxException, JSONException { - setUpPackage(vertx, configuration.getId(), STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE); - saveTag(vertx, FULL_PACKAGE_ID, PACKAGE, STUB_TAG_VALUE_2); - - mockGet(new RegexPattern(PROVIDER_PACKAGES_RM_API_PATH), STUB_PACKAGE_RESPONSE); - - String actual = getWithOk(PROVIDER_PACKAGES, STUB_USER_ID_HEADER).asString(); - String expected = readFile( - "responses/kb-ebsco/packages/expected-package-collection-with-one-element-with-tags.json"); - - JSONAssert.assertEquals(expected, actual, JSONCompareMode.LENIENT); - } - - @Test - public void shouldReturn400IfProviderIdInvalid() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/invalid/packages"); - } - - @Test - public void shouldReturn400IfCountOutOfRange() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?count=120"); - } - - @Test - public void shouldReturn400IfFilterTypeInvalid() { - checkResponseNotEmptyWhenStatusIs400( - PROVIDER_PACKAGES + "?q=Search&filter[selected]=true&filter[type]=unsupported"); - } - - @Test - public void shouldReturn400IfFilterSelectedInvalid() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?q=Search&filter[selected]=invalid"); - } - - @Test() - public void shouldReturn400IfPageOffsetInvalid() { - final ExtractableResponse<Response> response = getWithStatus( - PROVIDER_PACKAGES + "?q=Search&count=5&page=abc", SC_BAD_REQUEST); - assertThat(response.response().asString(), containsString("For input string: \"abc\"")); - } - - @Test - public void shouldReturn400IfSortInvalid() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?q=Search&sort=invalid"); - } - - @Test - public void shouldReturn400IfQueryParamInvalid() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PACKAGES + "?q="); - } - - @Test - public void shouldReturn404WhenNonProviderIdNotFound() { - String rmapiInvalidProviderIdUrl = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/191919/packages"; - - mockGet(new RegexPattern(rmapiInvalidProviderIdUrl), SC_NOT_FOUND); - - JsonapiError error = getWithStatus("/eholdings/providers/191919/packages", SC_NOT_FOUND, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Provider not found"); - } - - private void sendPutTags(List<String> newTags) throws IOException, URISyntaxException { - ProviderTagsPutRequest tags = readJsonFile(PUT_PROVIDER_TAGS, ProviderTagsPutRequest.class); - - if (newTags != null) { - tags.getData().getAttributes().setTags(new Tags() - .withTagList(newTags)); - } - - putWithOk(PROVIDER_TAGS_PATH, Json.encode(tags), STUB_USER_ID_HEADER).as(PackageTags.class); - } - - private void mockProviderWithName(String stubProviderId, String stubProviderName) { - mockGetWithBody(new RegexPattern(".*vendors/" + stubProviderId), - getProviderResponse(stubProviderName, stubProviderId)); - } - - private String getProviderResponse(String providerName, String providerId) { - return Json.encode(VendorById.byIdBuilder() - .vendorName(providerName) - .vendorId(Integer.parseInt(providerId)) - .build()); - } - - private void setUpTaggedProviders() { - String credentialsId = configuration.getId(); - ProvidersTestUtil.saveProvider(buildDbProvider(STUB_VENDOR_ID, credentialsId, STUB_VENDOR_NAME), vertx); - ProvidersTestUtil.saveProvider(buildDbProvider(STUB_VENDOR_ID_2, credentialsId, STUB_VENDOR_NAME_2), vertx); - ProvidersTestUtil.saveProvider(buildDbProvider(STUB_VENDOR_ID_3, credentialsId, STUB_VENDOR_NAME_3), vertx); - - mockProviderWithName(STUB_VENDOR_ID, STUB_VENDOR_NAME); - mockProviderWithName(STUB_VENDOR_ID_2, STUB_VENDOR_NAME_2); - mockProviderWithName(STUB_VENDOR_ID_3, STUB_VENDOR_NAME_3); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProxyTypesImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProxyTypesImplTest.java deleted file mode 100644 index 6b1b1562b..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProxyTypesImplTest.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static org.apache.http.HttpStatus.SC_FORBIDDEN; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.RmApiConstants.RMAPI_PROXIES_URL; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; - -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.util.KbCredentialsTestUtil; -import org.json.JSONException; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.skyscreamer.jsonassert.JSONAssert; - -@RunWith(VertxUnitRunner.class) -public class EholdingsProxyTypesImplTest extends WireMockTestBase { - - private static final String EHOLDINGS_PROXY_TYPES_URL = "eholdings/proxy-types"; - private static final String EHOLDINGS_PROXY_TYPES_BY_CREDENTIALS_ID_URL = "/eholdings/kb-credentials/%s/proxy-types"; - - @After - public void tearDown() { - clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnProxyTypesWhenUserAssignedToKbCredentials() - throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_PROXIES_URL), "responses/rmapi/proxytypes/get-proxy-types-response.json"); - - String actual = getWithStatus(EHOLDINGS_PROXY_TYPES_URL, SC_OK, JOHN_USER_ID_HEADER).asString(); - - String expected = readFile("responses/kb-ebsco/proxytypes/get-proxy-types-response.json"); - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturnProxyTypesWhenOneCredentialsExistsAndUserNotAssigned() - throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - mockGet(new RegexPattern(RMAPI_PROXIES_URL), "responses/rmapi/proxytypes/get-proxy-types-response.json"); - - String actual = getWithStatus(EHOLDINGS_PROXY_TYPES_URL, SC_OK, JOHN_USER_ID_HEADER).asString(); - - String expected = readFile("responses/kb-ebsco/proxytypes/get-proxy-types-response.json"); - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturnEmptyProxyTypesFromEmptyRmApiResponse() - throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - mockGet(new RegexPattern(RMAPI_PROXIES_URL), "responses/rmapi/proxytypes/get-proxy-types-empty-response.json"); - - String actual = getWithStatus(EHOLDINGS_PROXY_TYPES_URL, SC_OK, JOHN_USER_ID_HEADER).asString(); - - String expected = readFile("responses/kb-ebsco/proxytypes/get-proxy-types-empty-response.json"); - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturn404WhenUserNotAssignedToKbCredentials() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - KbCredentialsTestUtil - .saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME + "1", STUB_API_KEY, "OTHER_CUSTOMER_ID", vertx); - - JsonapiError error = - getWithStatus(EHOLDINGS_PROXY_TYPES_URL, SC_NOT_FOUND, JANE_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "KB Credentials do not exist or user with userId = " + JANE_ID - + " is not assigned to any available knowledgebase."); - } - - @Test - public void shouldReturn401WhenRmApiRequestCompletesWith401ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_PROXIES_URL), SC_UNAUTHORIZED); - final JsonapiError error = - getWithStatus(EHOLDINGS_PROXY_TYPES_URL, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturn403WhenRmApiRequestCompletesWith403ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_PROXIES_URL), SC_FORBIDDEN); - final JsonapiError error = - getWithStatus(EHOLDINGS_PROXY_TYPES_URL, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized"); - } - - @Test - public void shouldReturnProxyTypesCollection() throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - mockGet(new RegexPattern(RMAPI_PROXIES_URL), "responses/rmapi/proxytypes/get-proxy-types-response.json"); - - String resourcePath = String.format(EHOLDINGS_PROXY_TYPES_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - String actual = getWithOk(resourcePath).asString(); - - String expected = readFile("responses/kb-ebsco/proxytypes/get-proxy-types-response.json"); - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturn401WhenRmApiReturns401ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_PROXIES_URL), SC_UNAUTHORIZED); - final String path = String.format(EHOLDINGS_PROXY_TYPES_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - final JsonapiError error = getWithStatus(path, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturn403WhenRmApiReturns403ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_PROXIES_URL), SC_FORBIDDEN); - final String path = String.format(EHOLDINGS_PROXY_TYPES_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - final JsonapiError error = getWithStatus(path, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized"); - } - - @Test - public void shouldReturn404WhenCredentialsNotFound() { - final String path = - String.format(EHOLDINGS_PROXY_TYPES_BY_CREDENTIALS_ID_URL, "11111111-1111-1111-a111-111111111111"); - final JsonapiError error = getWithStatus(path, SC_NOT_FOUND, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "KbCredentials not found by id"); - } -} - diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java deleted file mode 100644 index 4c24f158d..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java +++ /dev/null @@ -1,686 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static java.lang.String.format; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.RecordType.RESOURCE; -import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; -import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.repository.resources.ResourceTableConstants.RESOURCES_TABLE_NAME; -import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_NAME; -import static org.folio.rest.impl.ResourcesTestData.STUB_CUSTOM_RESOURCE_ID; -import static org.folio.rest.impl.ResourcesTestData.STUB_MANAGED_RESOURCE_ID; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE_2; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_PACKAGE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_VENDOR_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_MANAGED_TITLE_ID; -import static org.folio.test.util.TestUtil.getFile; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.mockPut; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.test.util.TestUtil.readJsonFile; -import static org.folio.util.AccessTypesTestUtil.getAccessTypeMappings; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; -import static org.folio.util.AccessTypesTestUtil.testData; -import static org.folio.util.AssertTestUtil.assertEqualsResourceId; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.getDefaultKbConfiguration; -import static org.folio.util.KbTestUtil.setupDefaultKbConfiguration; -import static org.folio.util.TagsTestUtil.saveTag; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.EqualToJsonPattern; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.core.json.Json; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.folio.repository.RecordType; -import org.folio.repository.accesstypes.AccessTypeMapping; -import org.folio.repository.resources.DbResource; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.AccessType; -import org.folio.rest.jaxrs.model.Errors; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.KbCredentials; -import org.folio.rest.jaxrs.model.Resource; -import org.folio.rest.jaxrs.model.ResourceBulkFetchCollection; -import org.folio.rest.jaxrs.model.ResourcePutRequest; -import org.folio.rest.jaxrs.model.ResourceTags; -import org.folio.rest.jaxrs.model.ResourceTagsPutRequest; -import org.folio.rest.jaxrs.model.Tags; -import org.folio.util.ResourcesTestUtil; -import org.folio.util.TagsTestUtil; -import org.json.JSONException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.skyscreamer.jsonassert.JSONAssert; - -@RunWith(VertxUnitRunner.class) -public class EholdingsResourcesImplTest extends WireMockTestBase { - - private static final String MANAGED_PACKAGE_ENDPOINT = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages/" + STUB_PACKAGE_ID; - private static final String MANAGED_RESOURCE_ENDPOINT = MANAGED_PACKAGE_ENDPOINT + "/titles/" + STUB_MANAGED_TITLE_ID; - private static final String CUSTOM_RESOURCE_ENDPOINT = - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_CUSTOM_VENDOR_ID + "/packages/" + STUB_CUSTOM_PACKAGE_ID - + "/titles/" + STUB_CUSTOM_TITLE_ID; - private static final String STUB_MANAGED_RESOURCE_PATH = "eholdings/resources/" + STUB_MANAGED_RESOURCE_ID; - private static final String RESOURCE_TAGS_PATH = "eholdings/resources/" + STUB_CUSTOM_RESOURCE_ID + "/tags"; - private static final String RESOURCES_BULK_FETCH = "/eholdings/resources/bulk/fetch"; - - private KbCredentials configuration; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - configuration = getDefaultKbConfiguration(vertx); - } - - @After - public void tearDown() { - clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); - clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); - clearDataFromTable(vertx, TAGS_TABLE_NAME); - clearDataFromTable(vertx, RESOURCES_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnResourceWhenValidId() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-resource-by-id.json"; - - mockResource(stubResponseFile); - - String actualResponse = getWithOk(STUB_MANAGED_RESOURCE_PATH, STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, true); - } - - @Test - public void shouldReturnResourceWithTags() throws IOException, URISyntaxException { - saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); - String stubResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - - mockResource(stubResponseFile); - - Resource resource = getWithOk(STUB_MANAGED_RESOURCE_PATH, STUB_USER_ID_HEADER).as(Resource.class); - - assertTrue(resource.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); - } - - @Test - public void shouldReturnResourceWithTitleWhenTitleFlagSetToTrue() - throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-resource-by-id-with-title.json"; - - mockResource(stubResponseFile); - - String actualResponse = getWithOk("eholdings/resources/" + STUB_MANAGED_RESOURCE_ID + "?include=title", - STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, true); - } - - @Test - public void shouldReturnResourceWithProviderWhenProviderFlagSetToTrue() - throws IOException, URISyntaxException, JSONException { - String stubResourceResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - String stubVendorResponseFile = "responses/rmapi/vendors/get-vendor-by-id-for-resource.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-resource-by-id-with-provider.json"; - - mockResource(stubResourceResponseFile); - mockVendor(stubVendorResponseFile); - - String actualResponse = getWithOk("eholdings/resources/" + STUB_MANAGED_RESOURCE_ID + "?include=provider", - STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, true); - } - - @Test - public void shouldReturnResourceWithPackageWhenPackageFlagSetToTrue() - throws IOException, URISyntaxException, JSONException { - String stubResourceResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - String stubPackageResponseFile = "responses/rmapi/packages/get-package-by-id-for-resource.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-resource-by-id-with-package.json"; - - mockResource(stubResourceResponseFile); - mockPackage(stubPackageResponseFile); - - String actualResponse = getWithOk("eholdings/resources/" + STUB_MANAGED_RESOURCE_ID + "?include=package", - STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, true); - } - - @Test - public void shouldReturnResourceWithAllIncludedObjectsWhenIncludeContainsAllObjects() - throws IOException, URISyntaxException, JSONException { - final String stubResourceResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - final String stubVendorResponseFile = "responses/rmapi/vendors/get-vendor-by-id-for-resource.json"; - final String stubPackageResponseFile = "responses/rmapi/packages/get-package-by-id-for-resource.json"; - final String expectedResourceFile = "responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json"; - - mockResource(stubResourceResponseFile); - mockVendor(stubVendorResponseFile); - mockPackage(stubPackageResponseFile); - - String actualResponse = getWithOk( - "eholdings/resources/" + STUB_MANAGED_RESOURCE_ID + "?include=package,title,provider", STUB_USER_ID_HEADER) - .asString(); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, true); - } - - @Test - public void shouldReturn404WhenRmApiNotFoundOnResourceGet() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/resources/get-resource-by-id-not-found-response.json"; - - stubFor( - get(new UrlPathPattern(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)) - .withStatus(404))); - - JsonapiError error = getWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_NOT_FOUND, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Title is no longer in this package."); - } - - @Test - public void shouldReturn404WhenCustomerListIsEmpty() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/resources/get-resource-by-id-response-empty-customer-list.json"; - - mockResource(stubResponseFile); - - JsonapiError error = getWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_NOT_FOUND, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Title is no longer in this package"); - } - - @Test - public void shouldReturn400WhenValidationErrorOnResourceGet() { - JsonapiError error = getWithStatus("eholdings/resources/583-abc-762169", SC_BAD_REQUEST, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Resource id is invalid - 583-abc-762169"); - } - - @Test - public void shouldReturn500WhenRmApiReturns500ErrorOnResourceGet() { - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), SC_INTERNAL_SERVER_ERROR); - - JsonapiError error = - getWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_INTERNAL_SERVER_ERROR, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertThat(error.getErrors().getFirst().getTitle(), notNullValue()); - } - - @Test - public void shouldReturnUpdatedValuesManagedResourceOnSuccessfulPut() - throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/resources/get-managed-resource-updated-response.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-managed-resource.json"; - - String actualResponse = - mockUpdateResourceScenario(stubResponseFile, MANAGED_RESOURCE_ENDPOINT, STUB_MANAGED_RESOURCE_ID, - readFile("requests/kb-ebsco/resource/put-managed-resource.json")); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, false); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), true)) - .withRequestBody( - equalToJson(readFile("requests/rmapi/resources/put-managed-resource-is-selected-multiple-attributes.json")))); - } - - @Test - public void shouldCreateNewAccessTypeMappingOnSuccessfulPut() throws IOException, URISyntaxException, JSONException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - String accessTypeId = accessTypes.getFirst().getId(); - String stubResponseFile = "responses/rmapi/resources/get-managed-resource-updated-response.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-resource-by-id-with-access-type.json"; - - String requestBody = format(readFile("requests/kb-ebsco/resource/put-resource-with-access-type.json"), - accessTypeId); - String actualResponse = mockUpdateResourceScenario(stubResponseFile, MANAGED_RESOURCE_ENDPOINT, - STUB_MANAGED_RESOURCE_ID, requestBody); - - String expectedJson = format(readFile(expectedResourceFile), accessTypeId, accessTypeId); - JSONAssert.assertEquals(expectedJson, actualResponse, false); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), true)).withRequestBody( - equalToJson(readFile("requests/rmapi/resources/put-managed-resource-is-selected-multiple-attributes.json")))); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(1, accessTypeMappingsInDb.size()); - assertEquals(accessTypeId, accessTypeMappingsInDb.getFirst().getAccessTypeId().toString()); - assertEquals(RESOURCE, accessTypeMappingsInDb.getFirst().getRecordType()); - } - - @Test - public void shouldDeleteAccessTypeMappingOnSuccessfulPut() throws IOException, URISyntaxException, JSONException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - String accessTypeId = accessTypes.getFirst().getId(); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypeId, vertx); - - String stubResponseFile = "responses/rmapi/resources/get-managed-resource-updated-response.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-managed-resource.json"; - - String actualResponse = mockUpdateResourceScenario(stubResponseFile, MANAGED_RESOURCE_ENDPOINT, - STUB_MANAGED_RESOURCE_ID, readFile("requests/kb-ebsco/resource/put-managed-resource.json")); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, false); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), true)).withRequestBody( - equalToJson(readFile("requests/rmapi/resources/put-managed-resource-is-selected-multiple-attributes.json")))); - - List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); - assertEquals(0, accessTypeMappingsInDb.size()); - } - - @Test - public void shouldReturn400OnPutPackageWithNotExistedAccessType() throws URISyntaxException, IOException { - String requestBody = readFile("requests/kb-ebsco/resource/put-managed-resource-with-missing-access-type.json"); - - JsonapiError error = putWithStatus(STUB_MANAGED_RESOURCE_PATH, requestBody, SC_BAD_REQUEST, CONTENT_TYPE_HEADER, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - verify(0, putRequestedFor(new UrlPathPattern(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), true))); - - assertErrorContainsTitle(error, "Access type not found: id = 99999999-9999-1999-a999-999999999999"); - } - - @Test - public void shouldReturn422OnPutPackageWithInvalidAccessTypeId() throws URISyntaxException, IOException { - String requestBody = readFile("requests/kb-ebsco/resource/put-managed-resource-with-invalid-access-type.json"); - - Errors error = putWithStatus(STUB_MANAGED_RESOURCE_PATH, requestBody, SC_UNPROCESSABLE_ENTITY, CONTENT_TYPE_HEADER, - STUB_USER_ID_HEADER).as(Errors.class); - - verify(0, putRequestedFor(new UrlPathPattern(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), true))); - - assertEquals(1, error.getErrors().size()); - assertEquals( - "must match \"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[1-5][a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$\"", - error.getErrors().getFirst().getMessage()); - } - - @Test - public void shouldDeselectManagedResourceOnPutWithSelectedFalse() - throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/resources/get-managed-resource-updated-response-is-selected-false.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-managed-resource.json"; - - ResourcePutRequest request = - readJsonFile("requests/kb-ebsco/resource/put-managed-resource-is-not-selected.json", ResourcePutRequest.class); - request.getData().getAttributes().setIsSelected(false); - String actualResponse = - mockUpdateResourceScenario(stubResponseFile, MANAGED_RESOURCE_ENDPOINT, STUB_MANAGED_RESOURCE_ID, - Json.encode(request)); - - Resource expectedResource = readJsonFile(expectedResourceFile, Resource.class); - expectedResource.getData().getAttributes().setIsSelected(false); - JSONAssert.assertEquals(Json.encode(expectedResource), actualResponse, false); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), true)) - .withRequestBody( - new EqualToJsonPattern(readFile("requests/rmapi/resources/put-managed-resource-is-not-selected.json"), - true, true))); - } - - @Test - public void shouldReturnUpdatedValuesCustomResourceOnSuccessfulPut() - throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/resources/get-custom-resource-updated-response.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-custom-resource.json"; - - String actualResponse = - mockUpdateResourceScenario(stubResponseFile, CUSTOM_RESOURCE_ENDPOINT, STUB_CUSTOM_RESOURCE_ID, - readFile("requests/kb-ebsco/resource/put-custom-resource.json")); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, false); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(CUSTOM_RESOURCE_ENDPOINT), true)) - .withRequestBody( - equalToJson(readFile("requests/rmapi/resources/put-custom-resource-is-selected-multiple-attributes.json")))); - } - - @Test - public void shouldAcceptValuesCustomResourceWithUnrecognizedFieldInProxy() - throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/resources/get-custom-resource-updated-response.json"; - String expectedResourceFile = "responses/kb-ebsco/resources/expected-custom-resource.json"; - - String actualResponse = - mockUpdateResourceScenario(stubResponseFile, CUSTOM_RESOURCE_ENDPOINT, STUB_CUSTOM_RESOURCE_ID, - readFile("requests/kb-ebsco/resource/put-custom-resource-with-proxied-url.json")); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, false); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(CUSTOM_RESOURCE_ENDPOINT), true)) - .withRequestBody( - equalToJson(readFile("requests/rmapi/resources/put-custom-resource-is-selected-multiple-attributes.json")))); - } - - @Test - public void shouldUpdateTagsOnSuccessfulTagsPut() throws IOException, URISyntaxException { - List<String> tags = Collections.singletonList(STUB_TAG_VALUE); - sendPutTags(tags); - List<DbResource> resources = ResourcesTestUtil.getResources(vertx); - assertEquals(1, resources.size()); - assertEqualsResourceId(resources.getFirst().getId()); - assertEquals(STUB_VENDOR_NAME, resources.getFirst().getName()); - } - - @Test - public void shouldUpdateTagsOnSuccessfulTagsPutWithAlreadyExistingTags() throws IOException, URISyntaxException { - saveTag(vertx, STUB_CUSTOM_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); - List<String> newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); - sendPutTags(newTags); - List<String> tagsAfterRequest = TagsTestUtil.getTagsForRecordType(vertx, RecordType.RESOURCE); - assertThat(tagsAfterRequest, containsInAnyOrder(newTags.toArray())); - } - - @Test - public void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - ResourceTagsPutRequest tags = - mapper.readValue(getFile("requests/kb-ebsco/resource/put-resource-tags.json"), ResourceTagsPutRequest.class); - tags.getData().getAttributes().setName(""); - JsonapiError error = - putWithStatus(RESOURCE_TAGS_PATH, mapper.writeValueAsString(tags), SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid name"); - } - - @Test - public void shouldReturn422WhenInvalidUrlIsProvidedForCustomResource() throws URISyntaxException, IOException { - final String stubResponseFile = "responses/rmapi/resources/get-custom-resource-updated-response.json"; - final String invalidPutBody = readFile("requests/kb-ebsco/resource/put-custom-resource-invalid-url.json"); - - mockGet(new RegexPattern(CUSTOM_RESOURCE_ENDPOINT), stubResponseFile); - - JsonapiError error = - putWithStatus("eholdings/resources/" + STUB_CUSTOM_RESOURCE_ID, invalidPutBody, SC_UNPROCESSABLE_ENTITY, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid url"); - } - - @Test - public void shouldPostResourceToRmApi() throws IOException, URISyntaxException, JSONException { - final String stubTitleResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - final String stubPackageResponseFile = "responses/rmapi/packages/get-custom-package-by-id-response.json"; - final String stubPackageResourcesFile = "responses/rmapi/resources/get-resources-by-package-id-response.json"; - final String postStubRequest = "requests/kb-ebsco/resource/post-resources-request.json"; - final String expectedResourceFile = "responses/kb-ebsco/resources/expected-resource-after-post.json"; - - mockPackageResources(stubPackageResourcesFile); - mockPackage(stubPackageResponseFile); - mockTitle(stubTitleResponseFile); - mockResource(stubTitleResponseFile); - - EqualToJsonPattern putRequestBodyPattern = - new EqualToJsonPattern(readFile("requests/rmapi/resources/select-resource-request.json"), - true, true); - mockPut(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), putRequestBodyPattern, SC_NO_CONTENT); - - String actualResponse = - postWithOk("eholdings/resources", readFile(postStubRequest), STUB_USER_ID_HEADER).asString(); - - JSONAssert.assertEquals(readFile(expectedResourceFile), actualResponse, true); - - verify(1, putRequestedFor(new UrlPathPattern(new EqualToPattern(MANAGED_RESOURCE_ENDPOINT), false)) - .withRequestBody(putRequestBodyPattern)); - } - - @Test - public void shouldReturn404IfTitleOrPackageIsNotFound() throws IOException, URISyntaxException { - String postStubRequest = "requests/kb-ebsco/resource/post-resources-request.json"; - - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), SC_NOT_FOUND); - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT), SC_NOT_FOUND); - - JsonapiError error = - postWithStatus("eholdings/resources", readFile(postStubRequest), SC_NOT_FOUND, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "not found"); - } - - @Test - public void shouldReturn422IfPackageIsNotCustom() throws IOException, URISyntaxException { - final String stubTitleResponseFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - final String stubPackageResponseFile = "responses/rmapi/packages/get-package-by-id-for-resource.json"; - final String stubPackageResourcesFile = "responses/rmapi/resources/get-resources-by-package-id-response.json"; - final String postStubRequest = "requests/kb-ebsco/resource/post-resources-request.json"; - - mockPackageResources(stubPackageResourcesFile); - mockPackage(stubPackageResponseFile); - mockTitle(stubTitleResponseFile); - - JsonapiError error = - postWithStatus("eholdings/resources", readFile(postStubRequest), SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertThat(error.getErrors().getFirst().getTitle(), containsString("Invalid PackageId")); - } - - @Test - public void shouldSendDeleteRequestForResourceAssociatedWithCustomPackage() throws IOException, URISyntaxException { - EqualToJsonPattern putBodyPattern = new EqualToJsonPattern("{\"isSelected\":false}", true, true); - deleteResource(putBodyPattern); - verify(1, putRequestedFor(new UrlPathPattern(new EqualToPattern(CUSTOM_RESOURCE_ENDPOINT), false)) - .withRequestBody(putBodyPattern)); - } - - @Test - public void shouldDeleteTagsOnDeleteRequest() throws IOException, URISyntaxException { - saveTag(vertx, STUB_CUSTOM_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); - EqualToJsonPattern putBodyPattern = new EqualToJsonPattern("{\"isSelected\":false}", true, true); - deleteResource(putBodyPattern); - List<String> actualTags = TagsTestUtil.getTags(vertx); - assertThat(actualTags, empty()); - } - - @Test - public void shouldDeleteAccessTypeOnDeleteRequest() throws IOException, URISyntaxException { - String accessTypeId = insertAccessTypes(testData(configuration.getId()), vertx).getFirst().getId(); - insertAccessTypeMapping(STUB_CUSTOM_RESOURCE_ID, RecordType.RESOURCE, accessTypeId, vertx); - EqualToJsonPattern putBodyPattern = new EqualToJsonPattern("{\"isSelected\":false}", true, true); - deleteResource(putBodyPattern); - List<AccessTypeMapping> actualMappings = getAccessTypeMappings(vertx); - assertThat(actualMappings, empty()); - } - - @Test - public void shouldReturn400WhenResourceIdIsInvalid() { - JsonapiError error = - deleteWithStatus("eholdings/resources/abc-def", SC_BAD_REQUEST, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Resource id is invalid"); - } - - @Test - public void shouldReturn400WhenTryingToDeleteResourceAssociatedWithManagedPackage() - throws URISyntaxException, IOException { - String stubResponseFile = "responses/rmapi/resources/get-managed-resource-updated-response.json"; - - mockGet(new EqualToPattern(MANAGED_RESOURCE_ENDPOINT), stubResponseFile); - JsonapiError error = - deleteWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_BAD_REQUEST, STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Resource cannot be deleted"); - } - - @Test - public void shouldReturnListWithBulkFetchResources() throws IOException, URISyntaxException, JSONException { - String postBody = readFile("requests/kb-ebsco/resource/post-resources-bulk.json"); - String expectedResourceFile = "responses/kb-ebsco/resources/expected-resources-bulk-response.json"; - String responseRmApiFile = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - - mockGet(new EqualToPattern(MANAGED_RESOURCE_ENDPOINT), responseRmApiFile); - - final String actualResponse = - postWithOk("/eholdings/resources/bulk/fetch", postBody, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals( - readFile(expectedResourceFile), actualResponse, true); - } - - @Test - public void shouldReturn422OnInvalidIdFormat() throws IOException, URISyntaxException { - String postBody = readFile("requests/kb-ebsco/resource/post-resources-bulk-with-invalid-id-format.json"); - - final Errors error = postWithStatus(RESOURCES_BULK_FETCH, postBody, SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(Errors.class); - assertThat(error.getErrors().getFirst().getMessage(), equalTo("elements in list must match pattern")); - } - - @Test - public void shouldReturnResponseWhenIdIsTooLong() throws IOException, URISyntaxException, JSONException { - String postBody = readFile("requests/kb-ebsco/resource/post-resource-with-too-long-id.json"); - String expectedResourceFile = "responses/kb-ebsco/resources/expected-response-on-too-long-id.json"; - - final String actualResponse = postWithOk(RESOURCES_BULK_FETCH, postBody, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals( - readFile(expectedResourceFile), actualResponse, false); - } - - @Test - public void shouldReturnResourcesAndFailedIds() throws IOException, URISyntaxException, JSONException { - final String postBody = readFile("requests/kb-ebsco/resource/post-resources-bulk-with-invalid-ids.json"); - final String expectedResourceFile = "responses/kb-ebsco/resources/expected-resources-bulk" - + "-response-with-failed-ids.json"; - final String resourceResponse1 = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - final String resourceResponse2 = "responses/rmapi/resources/get-custom-resource-updated-response.json"; - final String notFoundResponse = "responses/rmapi/resources/get-resource-by-id-not-found-response.json"; - - mockGet(new EqualToPattern(MANAGED_RESOURCE_ENDPOINT), resourceResponse1); - mockGet(new EqualToPattern(CUSTOM_RESOURCE_ENDPOINT), resourceResponse2); - - stubFor( - get(new UrlPathPattern( - new EqualToPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/186/packages/3150130/titles/19087948"), - false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(notFoundResponse)) - .withStatus(404))); - - final String actualResponse = postWithOk(RESOURCES_BULK_FETCH, postBody, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals( - readFile(expectedResourceFile), actualResponse, false); - } - - @Test - public void shouldReturnErrorWhenRmApiFails() throws IOException, URISyntaxException { - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), SC_INTERNAL_SERVER_ERROR); - - String postBody = readFile("requests/kb-ebsco/resource/post-resources-bulk.json"); - final ResourceBulkFetchCollection bulkFetchCollection = postWithOk(RESOURCES_BULK_FETCH, postBody, - STUB_USER_ID_HEADER).as(ResourceBulkFetchCollection.class); - - assertThat(bulkFetchCollection.getIncluded().size(), equalTo(0)); - assertThat(bulkFetchCollection.getMeta().getFailed().getResources().size(), equalTo(1)); - assertThat(bulkFetchCollection.getMeta().getFailed().getResources().getFirst(), equalTo("19-3964-762169")); - } - - private void mockPackageResources(String stubPackageResourcesFile) throws IOException, URISyntaxException { - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), stubPackageResourcesFile); - } - - private void mockPackage(String responseFile) throws IOException, URISyntaxException { - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT), responseFile); - } - - private void mockResource(String responseFile) throws IOException, URISyntaxException { - mockGet(new RegexPattern(MANAGED_RESOURCE_ENDPOINT), responseFile); - } - - private void mockTitle(String responseFile) throws IOException, URISyntaxException { - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), responseFile); - } - - private void mockVendor(String responseFile) throws IOException, URISyntaxException { - mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID), responseFile); - } - - private String mockUpdateResourceScenario(String updatedResourceResponseFile, String resourceEndpoint, - String resourceId, - String requestBody) throws IOException, URISyntaxException { - stubFor( - get(new UrlPathPattern(new RegexPattern(resourceEndpoint), false)) - .willReturn(new ResponseDefinitionBuilder().withBody(readFile(updatedResourceResponseFile)))); - - stubFor( - put(new UrlPathPattern(new RegexPattern(resourceEndpoint), true)) - .willReturn(new ResponseDefinitionBuilder().withStatus(SC_NO_CONTENT))); - - return putWithOk("eholdings/resources/" + resourceId, requestBody, STUB_USER_ID_HEADER).asString(); - } - - private void sendPutTags(List<String> newTags) throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - ResourceTagsPutRequest tags = - mapper.readValue(getFile("requests/kb-ebsco/resource/put-resource-tags.json"), ResourceTagsPutRequest.class); - - if (newTags != null) { - tags.getData().getAttributes().setTags(new Tags() - .withTagList(newTags)); - } - - putWithOk(RESOURCE_TAGS_PATH, mapper.writeValueAsString(tags), STUB_USER_ID_HEADER).as(ResourceTags.class); - } - - private void deleteResource(EqualToJsonPattern putBodyPattern) - throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/resources/get-custom-resource-updated-response.json"; - - mockGet(new EqualToPattern(CUSTOM_RESOURCE_ENDPOINT), stubResponseFile); - mockPut(new EqualToPattern(CUSTOM_RESOURCE_ENDPOINT), putBodyPattern, SC_NO_CONTENT); - - deleteWithNoContent("eholdings/resources/" + STUB_CUSTOM_RESOURCE_ID, STUB_USER_ID_HEADER); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsRootProxyImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsRootProxyImplTest.java deleted file mode 100644 index 2b74ed0a1..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsRootProxyImplTest.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_FORBIDDEN; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.folio.repository.assigneduser.AssignedUsersConstants.ASSIGNED_USERS_TABLE_NAME; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.RmApiConstants.RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.mockPut; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.AssignedUsersTestUtil.saveAssignedUser; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.json.JSONException; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.skyscreamer.jsonassert.JSONAssert; - -@RunWith(VertxUnitRunner.class) -public class EholdingsRootProxyImplTest extends WireMockTestBase { - - private static final String EHOLDINGS_ROOT_PROXY_URL = "eholdings/root-proxy"; - private static final String EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL = "/eholdings/kb-credentials/%s/root-proxy"; - - private static final String RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE = - "responses/rmapi/proxiescustomlabels/get-success-response.json"; - private static final String KB_EBSCO_GET_ROOT_PROXY_RESPONSE = - "responses/kb-ebsco/root-proxy/get-root-proxy-response.json"; - - @After - public void tearDown() { - clearDataFromTable(vertx, ASSIGNED_USERS_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnRootProxyWhenUserAssignedToKbCredentials() - throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE); - - String actual = getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_OK, JOHN_USER_ID_HEADER).asString(); - - String expected = readFile(KB_EBSCO_GET_ROOT_PROXY_RESPONSE); - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturnRootProxyWhenOneCredentialsExistsAndUserNotAssigned() - throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE); - - String actual = getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_OK, JOHN_USER_ID_HEADER).asString(); - - String expected = readFile(KB_EBSCO_GET_ROOT_PROXY_RESPONSE); - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturn404WhenUserNotAssignedToKbCredentials() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - saveKbCredentials(getWiremockUrl(), STUB_CREDENTIALS_NAME + "1", STUB_API_KEY, "OTHER_CUSTOMER_ID", vertx); - - JsonapiError error = - getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_NOT_FOUND, JANE_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "KB Credentials do not exist or user with userId = " + JANE_ID - + " is not assigned to any available knowledgebase."); - } - - @Test - public void shouldReturn401WhenRmApiRequestCompletesWith401ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), SC_UNAUTHORIZED); - final JsonapiError error = - getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturn403WhenRmApiRequestCompletesWith403ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), SC_FORBIDDEN); - final JsonapiError error = - getWithStatus(EHOLDINGS_ROOT_PROXY_URL, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized"); - } - - @Test - public void shouldReturnRootProxyWhenUserAssignedToCredentials() - throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), RMAPI_ROOT_PROXY_CUSTOM_LABELS_RESPONSE); - - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - String actual = getWithStatus(path, SC_OK, JOHN_USER_ID_HEADER).asString(); - - String expected = readFile(KB_EBSCO_GET_ROOT_PROXY_RESPONSE); - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturn401WhenRmApiReturns401ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), SC_UNAUTHORIZED); - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - final JsonapiError error = getWithStatus(path, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturn403WhenRmApiReturns403ErrorStatus() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveAssignedUser(JOHN_ID, STUB_CREDENTIALS_ID, vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), SC_FORBIDDEN); - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - final JsonapiError error = getWithStatus(path, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized"); - } - - @Test - public void shouldReturn404WhenCredentialsNotFound() { - final String path = - String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, "11111111-1111-1111-a111-111111111111"); - final JsonapiError error = getWithStatus(path, SC_NOT_FOUND, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "KbCredentials not found by id"); - } - - @Test - public void shouldReturnUpdatedProxyOnSuccessfulPut() throws IOException, URISyntaxException, JSONException { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - String stubResponseFile = "responses/rmapi/proxiescustomlabels/get-updated-response.json"; - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), stubResponseFile); - mockPut(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), SC_NO_CONTENT); - - String expected = readFile("responses/kb-ebsco/root-proxy/put-root-proxy-response-updated.json"); - - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - - String actual = putWithOk(path, readFile("requests/kb-ebsco/put-root-proxy.json")).asString(); - - JSONAssert.assertEquals(expected, actual, true); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), true)) - .withRequestBody(equalToJson(readFile("requests/rmapi/proxiescustomlabels/put-root-proxy.json")))); - } - - @Test - public void shouldReturn400WhenInvalidProxyIdAndRmApiErrorOnPut() throws IOException, URISyntaxException { - String stubGetResponseFile = "responses/rmapi/proxiescustomlabels/get-updated-response.json"; - String stubPutResponseFile = "responses/rmapi/proxiescustomlabels/put-400-error-response.json"; - - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - mockGet(new EqualToPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), stubGetResponseFile); - stubFor( - put(new UrlPathPattern(new EqualToPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), false)) - .willReturn( - new ResponseDefinitionBuilder().withBody(readFile(stubPutResponseFile)).withStatus(SC_BAD_REQUEST))); - - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - JsonapiError error = - putWithStatus(path, readFile("requests/kb-ebsco/put-root-proxy.json"), SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid Proxy ID"); - } - - @Test - public void shouldReturnNotFoundWhenNoKbCredentialsStored() throws IOException, URISyntaxException { - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - JsonapiError error = - putWithStatus(path, readFile("requests/kb-ebsco/put-root-proxy.json"), SC_NOT_FOUND).as(JsonapiError.class); - assertErrorContainsTitle(error, "KbCredentials not found by id"); - } - - @Test - public void shouldReturn401WhenRmApiReturns401() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), SC_UNAUTHORIZED); - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - final JsonapiError error = getWithStatus(path, SC_UNAUTHORIZED, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized Access"); - } - - @Test - public void shouldReturn403WhenRmApiReturns403() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - - mockGet(new RegexPattern(RMAPI_ROOT_PROXY_CUSTOM_LABELS_URL), SC_FORBIDDEN); - final String path = String.format(EHOLDINGS_ROOT_PROXY_BY_CREDENTIALS_ID_URL, STUB_CREDENTIALS_ID); - final JsonapiError error = getWithStatus(path, SC_FORBIDDEN, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Unauthorized"); - } -} - diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsStatusTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsStatusTest.java deleted file mode 100644 index 594200130..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsStatusTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.STUB_TOKEN; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.setupDefaultKbConfiguration; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.restassured.RestAssured; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import org.folio.okapi.common.XOkapiHeaders; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.ConfigurationStatus; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.util.AssertTestUtil; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(VertxUnitRunner.class) -public class EholdingsStatusTest extends WireMockTestBase { - - public static final String EHOLDINGS_STATUS_PATH = "eholdings/status"; - - @After - public void tearDown() { - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnTrueWhenRmApiRequestCompletesWith200Status() throws IOException, URISyntaxException { - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile("responses/rmapi/vendors/get-zero-vendors-response.json")))); - - final ConfigurationStatus status = - getWithOk(EHOLDINGS_STATUS_PATH, STUB_USER_ID_HEADER).as(ConfigurationStatus.class); - assertThat(status.getData().getAttributes().getIsConfigurationValid(), equalTo(true)); - } - - @Test - public void shouldReturnFalseWhenRmApiRequestCompletesWithErrorStatus() { - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts.*"), true)) - .willReturn(new ResponseDefinitionBuilder().withStatus(401))); - - final ConfigurationStatus status = - getWithOk(EHOLDINGS_STATUS_PATH, STUB_USER_ID_HEADER).as(ConfigurationStatus.class); - assertThat(status.getData().getAttributes().getIsConfigurationValid(), equalTo(false)); - } - - @Test - public void shouldReturnErrorWhenRmApiRequestCompletesWith429() { - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts.*"), true)) - .willReturn(new ResponseDefinitionBuilder().withStatus(429).withBody(""" - { - "Errors": [ - { - "Code": 1010, - "Message": "Too Many Requests.", - "SubCode": 0 - } - ] - }"""))); - - final JsonapiError error = getWithStatus(EHOLDINGS_STATUS_PATH, 429, STUB_USER_ID_HEADER).as(JsonapiError.class); - AssertTestUtil.assertErrorContainsTitle(error, "Too Many Requests"); - } - - @Test - public void shouldReturn500OnInvalidOkapiUrl() { - RestAssured.given() - .header(XOkapiHeaders.TENANT, STUB_TENANT) - .header(XOkapiHeaders.TOKEN, STUB_TOKEN) - .header(XOkapiHeaders.URL, "wrongUrl^") - .baseUri("http://localhost") - .port(port) - .when() - .get(EHOLDINGS_STATUS_PATH) - .then() - .statusCode(500); - } - - @Test - public void shouldReturnFalseIfEmptyConfig() { - final ConfigurationStatus status = - getWithOk(EHOLDINGS_STATUS_PATH, STUB_USER_ID_HEADER).as(ConfigurationStatus.class); - - assertThat(status.getData().getAttributes().getIsConfigurationValid(), equalTo(false)); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTagsImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTagsImplTest.java deleted file mode 100644 index ead77dea2..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTagsImplTest.java +++ /dev/null @@ -1,211 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static java.util.Arrays.asList; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.folio.common.ListUtils.mapItems; -import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.TagsTestUtil.saveTags; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.function.Predicate; -import org.apache.commons.collections4.CollectionUtils; -import org.folio.repository.RecordType; -import org.folio.repository.tag.DbTag; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.MetaTotalResults; -import org.folio.rest.jaxrs.model.TagCollection; -import org.folio.rest.jaxrs.model.TagCollectionItem; -import org.folio.rest.jaxrs.model.TagUniqueCollection; -import org.folio.rest.util.RestConstants; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.convert.converter.Converter; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class EholdingsTagsImplTest extends WireMockTestBase { - - private static final String PROVIDER_ID = "1111"; - private static final String PACKAGE_ID = PROVIDER_ID + "-" + "3964"; - private static final DbTag PACKAGE_TAG = tag(PACKAGE_ID, RecordType.PACKAGE, "package-tag"); - private static final String TITLE_ID = "12345"; - private static final String RESOURCE_ID = PACKAGE_ID + "-" + TITLE_ID; - private static final DbTag RESOURCE_TAG = tag(RESOURCE_ID, RecordType.RESOURCE, "resource-tag"); - private static final DbTag PROVIDER_TAG = tag(PROVIDER_ID, RecordType.PROVIDER, "provider-tag"); - private static final DbTag TITLE_TAG = tag(TITLE_ID, RecordType.TITLE, "title-tag"); - private static final List<DbTag> ALL_TAGS = asList(PROVIDER_TAG, PACKAGE_TAG, TITLE_TAG, RESOURCE_TAG); - private static final List<DbTag> UNIQUE_TAGS = asList(PROVIDER_TAG, PACKAGE_TAG, PACKAGE_TAG, TITLE_TAG, RESOURCE_TAG, - RESOURCE_TAG); - - @Autowired - private Converter<DbTag, TagCollectionItem> tagConverter; - - private static DbTag tag(String recordId, RecordType recordType, String value) { - return DbTag.builder() - .recordId(recordId) - .recordType(recordType) - .value(value).build(); - } - - @After - public void tearDown() { - clearDataFromTable(vertx, TAGS_TABLE_NAME); - } - - @Test - public void shouldReturnAllTagsSortedIfNotFilteredOnGet() { - List<DbTag> tags = saveTags(ALL_TAGS, vertx); - - TagCollection col = getWithOk("eholdings/tags").as(TagCollection.class); - - TagCollection expected = buildTagCollection(tags); - assertEquals(expected, col); - } - - @Test - public void shouldReturnEmptyCollectionIfNoTagsOnGet() { - TagCollection col = getWithOk("eholdings/tags").as(TagCollection.class); - - TagCollection expected = buildTagCollection(Collections.emptyList()); - assertEquals(expected, col); - } - - @Test - public void shouldFilterByRecordTypeOnGet() { - List<DbTag> tags = saveTags(ALL_TAGS, vertx); - - TagCollection col = getWithOk("eholdings/tags?filter[rectype]=provider").as(TagCollection.class); - - TagCollection expected = buildTagCollection(filter(tags, similarTo(PROVIDER_TAG))); - assertEquals(expected, col); - } - - @Test - public void shouldFilterBySeveralRecordTypesOnGet() { - List<DbTag> tags = saveTags(ALL_TAGS, vertx); - - TagCollection col = getWithOk("eholdings/tags?filter[rectype]=provider&filter[rectype]=title").as( - TagCollection.class); - - TagCollection expected = buildTagCollection(filter(tags, similarTo(PROVIDER_TAG).or(similarTo(TITLE_TAG)))); - assertEquals(expected, col); - } - - @Test - public void shouldReturnEmptyCollectionIfFilteredOutOnGet() { - saveTags(asList(PROVIDER_TAG, PACKAGE_TAG), vertx); - - TagCollection col = getWithOk("eholdings/tags?filter[rectype]=title").as(TagCollection.class); - - TagCollection expected = buildTagCollection(Collections.emptyList()); - assertEquals(expected, col); - } - - @Test - public void shouldFailOnInvalidRecordTypeOnGet() { - JsonapiError error = getWithStatus("eholdings/tags?filter[rectype]=INVALID&filter[rectype]=title", - SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid 'filter[rectype]' parameter value"); - } - - @Test - public void shouldReturnAllUniqueTags() { - List<String> tags = mapItems(saveTags(UNIQUE_TAGS, vertx), DbTag::getValue); - - TagUniqueCollection col = getWithOk("eholdings/tags/summary").as(TagUniqueCollection.class); - - assertEquals(4, col.getData().size()); - assertEquals(Integer.valueOf(4), col.getMeta().getTotalResults()); - assertTrue(checkContainingOfUniqueTags(tags, col)); - } - - @Test - public void shouldReturnEmptyUniqueTagsCollection() { - TagUniqueCollection col = getWithOk("eholdings/tags/summary").as(TagUniqueCollection.class); - - assertEquals(0, col.getData().size()); - assertEquals(Integer.valueOf(0), col.getMeta().getTotalResults()); - } - - @Test - public void shouldReturnListOfUniqueTagsWithParamsResources() { - List<String> tags = mapItems(saveTags(UNIQUE_TAGS, vertx), DbTag::getValue); - - TagUniqueCollection col = getWithOk("eholdings/tags/summary?filter[rectype]=resource").as( - TagUniqueCollection.class); - - assertEquals(1, col.getData().size()); - assertEquals(Integer.valueOf(1), col.getMeta().getTotalResults()); - assertTrue(checkContainingOfUniqueTags(tags, col)); - } - - @Test - public void shouldReturnListOfUniqueTagsWithMultipleParams() { - List<String> tags = mapItems(saveTags(UNIQUE_TAGS, vertx), DbTag::getValue); - - TagUniqueCollection col = getWithOk("eholdings/tags/summary?filter[rectype]=resource&filter[rectype]=provider").as( - TagUniqueCollection.class); - - assertEquals(2, col.getData().size()); - assertEquals(Integer.valueOf(2), col.getMeta().getTotalResults()); - assertTrue(checkContainingOfUniqueTags(tags, col)); - } - - @Test - public void shouldReturnBadRequestWithInvalidParams() { - JsonapiError error = getWithStatus("eholdings/tags/summary?filter[rectype]=INVALID&filter[rectype]=title", - SC_BAD_REQUEST).as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid 'filter[rectype]' parameter value"); - } - - private boolean checkContainingOfUniqueTags(List<String> source, TagUniqueCollection collection) { - return source.containsAll(mapItems(collection.getData(), - tagUniqueCollectionItem -> tagUniqueCollectionItem.getAttributes().getValue())); - } - - private List<TagCollectionItem> toTagCollectionItems(List<DbTag> tags) { - return mapItems(tags, tagConverter::convert); - } - - private List<TagCollectionItem> sort(List<TagCollectionItem> items) { - ArrayList<TagCollectionItem> result = new ArrayList<>(items); - result.sort(Comparator.comparing(o -> o.getAttributes().getValue())); - return result; - } - - private TagCollection buildTagCollection(List<DbTag> tags) { - return new TagCollection() - .withData(sort(toTagCollectionItems(tags))) - .withMeta(new MetaTotalResults().withTotalResults(tags.size())) - .withJsonapi(RestConstants.JSONAPI); - } - - private List<DbTag> filter(List<DbTag> tags, Predicate<DbTag> filter) { - List<DbTag> found = tags.stream().filter(filter).toList(); - - if (CollectionUtils.isEmpty(found)) { - throw new IllegalArgumentException("Cannot find any tag matching the filter predicate"); - } else { - return found; - } - } - - private Predicate<DbTag> similarTo(DbTag expected) { - return tag -> expected.getValue().equals(tag.getValue()) - && expected.getRecordId().equals(tag.getRecordId()) - && expected.getRecordType().equals(tag.getRecordType()); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTitlesTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTitlesTest.java deleted file mode 100644 index ad68076dd..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTitlesTest.java +++ /dev/null @@ -1,666 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.put; -import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; -import static org.folio.repository.RecordType.RESOURCE; -import static org.folio.repository.accesstypes.AccessTypeMappingsTableConstants.ACCESS_TYPES_MAPPING_TABLE_NAME; -import static org.folio.repository.accesstypes.AccessTypesTableConstants.ACCESS_TYPES_TABLE_NAME; -import static org.folio.repository.holdings.HoldingsTableConstants.HOLDINGS_TABLE; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.repository.resources.ResourceTableConstants.RESOURCES_TABLE_NAME; -import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; -import static org.folio.repository.titles.TitlesTableConstants.TITLES_TABLE_NAME; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.ResourcesTestData.STUB_MANAGED_RESOURCE_ID; -import static org.folio.rest.impl.ResourcesTestData.STUB_MANAGED_RESOURCE_ID_2; -import static org.folio.rest.impl.ResourcesTestData.STUB_MANAGED_RESOURCE_ID_3; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE; -import static org.folio.rest.impl.TagsTestData.STUB_TAG_VALUE_2; -import static org.folio.rest.impl.TitlesTestData.CUSTOM_RESOURCE_ENDPOINT; -import static org.folio.rest.impl.TitlesTestData.CUSTOM_TITLE_ENDPOINT; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_TITLE_NAME; -import static org.folio.rest.impl.TitlesTestData.STUB_MANAGED_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_MANAGED_TITLE_ID_2; -import static org.folio.rest.impl.TitlesTestData.STUB_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_TITLE_NAME; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME; -import static org.folio.util.AccessTypesTestUtil.STUB_ACCESS_TYPE_NAME_2; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypeMapping; -import static org.folio.util.AccessTypesTestUtil.insertAccessTypes; -import static org.folio.util.AccessTypesTestUtil.testData; -import static org.folio.util.AssertTestUtil.assertEqualsLong; -import static org.folio.util.AssertTestUtil.assertErrorContainsTitle; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.getDefaultKbConfiguration; -import static org.folio.util.KbTestUtil.setupDefaultKbConfiguration; -import static org.folio.util.ResourcesTestUtil.buildResource; -import static org.folio.util.ResourcesTestUtil.saveResource; -import static org.folio.util.TagsTestUtil.saveTag; -import static org.folio.util.TitlesTestUtil.mockGetTitles; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.folio.repository.RecordType; -import org.folio.repository.titles.DbTitle; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.AccessType; -import org.folio.rest.jaxrs.model.Errors; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.KbCredentials; -import org.folio.rest.jaxrs.model.Tags; -import org.folio.rest.jaxrs.model.Title; -import org.folio.rest.jaxrs.model.TitleCollection; -import org.folio.rest.jaxrs.model.TitleCollectionItem; -import org.folio.rest.jaxrs.model.TitlePostRequest; -import org.folio.rest.jaxrs.model.TitlePutRequest; -import org.folio.util.TagsTestUtil; -import org.folio.util.TitlesTestUtil; -import org.json.JSONException; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.skyscreamer.jsonassert.JSONAssert; - -@RunWith(VertxUnitRunner.class) -public class EholdingsTitlesTest extends WireMockTestBase { - - private static final String EHOLDINGS_TITLES_PATH = "eholdings/titles"; - - private KbCredentials configuration; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - setupDefaultKbConfiguration(getWiremockUrl(), vertx); - configuration = getDefaultKbConfiguration(vertx); - } - - @After - public void tearDown() { - clearDataFromTable(vertx, ACCESS_TYPES_MAPPING_TABLE_NAME); - clearDataFromTable(vertx, ACCESS_TYPES_TABLE_NAME); - clearDataFromTable(vertx, HOLDINGS_TABLE); - clearDataFromTable(vertx, TAGS_TABLE_NAME); - clearDataFromTable(vertx, TITLES_TABLE_NAME); - clearDataFromTable(vertx, RESOURCES_TABLE_NAME); - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } - - @Test - public void shouldReturnTitlesOnGet() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/titles/searchTitles.json"; - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)))); - - String resourcePath = EHOLDINGS_TITLES_PATH + "?page=1&filter[name]=Mind&sort=name"; - String actualResponse = getWithOk(resourcePath, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals(readFile("responses/kb-ebsco/titles/expected-titles.json"), actualResponse, true); - } - - @Test - public void shouldReturnTitlesOnGetWithResources() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/titles/searchTitles.json"; - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)))); - - String resourcePath = EHOLDINGS_TITLES_PATH + "?page=1&filter[name]=Mind&sort=name&include=resources"; - String actualResponse = getWithOk(resourcePath, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals(readFile("responses/kb-ebsco/titles/expected-titles-with-resources.json"), actualResponse, - true); - } - - @Test - public void shouldReturnTitlesOnSearchByTags() throws IOException, URISyntaxException, JSONException { - String stubResponseFile1 = "responses/rmapi/titles/get-title-by-id-response.json"; - String stubResponseFile2 = "responses/rmapi/titles/get-title-by-id-2-response.json"; - - stubFor( - get(urlMatching("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_MANAGED_TITLE_ID)) - .willReturn(aResponse().withBody(readFile(stubResponseFile1)))); - - stubFor( - get(urlMatching("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_MANAGED_TITLE_ID_2)) - .willReturn(aResponse().withBody(readFile(stubResponseFile2)))); - - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, configuration.getId(), STUB_TITLE_NAME), vertx); - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_2, configuration.getId(), STUB_CUSTOM_TITLE_NAME), vertx); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID_2, RecordType.RESOURCE, STUB_TAG_VALUE_2); - - String resourcePath = - EHOLDINGS_TITLES_PATH + "?filter[tags]=" + STUB_TAG_VALUE + "&filter[tags]=" + STUB_TAG_VALUE_2; - String actualResponse = getWithOk(resourcePath, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals(readFile("responses/kb-ebsco/titles/expected-tagged-titles.json"), actualResponse, true); - } - - @Test - public void shouldReturnTitlesOnSearchByTagsWithResources() throws IOException, URISyntaxException, JSONException { - String stubResponseFile1 = "responses/rmapi/titles/get-title-by-id-response.json"; - String stubResponseFile2 = "responses/rmapi/titles/get-title-by-id-2-response.json"; - - stubFor( - get(urlMatching("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_MANAGED_TITLE_ID)) - .willReturn(aResponse().withBody(readFile(stubResponseFile1)))); - - stubFor( - get(urlMatching("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_MANAGED_TITLE_ID_2)) - .willReturn(aResponse().withBody(readFile(stubResponseFile2)))); - - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, configuration.getId(), STUB_TITLE_NAME), vertx); - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_2, configuration.getId(), STUB_CUSTOM_TITLE_NAME), vertx); - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_3, configuration.getId(), STUB_CUSTOM_TITLE_NAME), vertx); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID_2, RecordType.RESOURCE, STUB_TAG_VALUE_2); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID_3, RecordType.RESOURCE, STUB_TAG_VALUE_2); - - String resourcePath = - EHOLDINGS_TITLES_PATH + "?filter[tags]=" + STUB_TAG_VALUE + "&filter[tags]=" + STUB_TAG_VALUE_2 - + "&include=resources"; - String actualResponse = getWithOk(resourcePath, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals(readFile("responses/kb-ebsco/titles/expected-tagged-titles-with-resources.json"), - actualResponse, true); - } - - @Test - public void shouldReturnSecondTitleOnSearchByTagsWithPagination() throws IOException, URISyntaxException { - String stubResponseFile1 = "responses/rmapi/titles/get-title-by-id-response.json"; - String stubResponseFile2 = "responses/rmapi/titles/get-title-by-id-2-response.json"; - - stubFor( - get(urlMatching("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_MANAGED_TITLE_ID)) - .willReturn(aResponse().withBody(readFile(stubResponseFile1)))); - - stubFor( - get(urlMatching("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_MANAGED_TITLE_ID_2)) - .willReturn(aResponse().withBody(readFile(stubResponseFile2)))); - - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID, configuration.getId(), STUB_TITLE_NAME), vertx); - saveResource(buildResource(STUB_MANAGED_RESOURCE_ID_2, configuration.getId(), STUB_CUSTOM_TITLE_NAME), vertx); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); - saveTag(vertx, STUB_MANAGED_RESOURCE_ID_2, RecordType.RESOURCE, STUB_TAG_VALUE_2); - - String resourcePath = EHOLDINGS_TITLES_PATH + "?page=2&count=1&filter[tags]=" - + STUB_TAG_VALUE + "&filter[tags]=" + STUB_TAG_VALUE_2; - TitleCollection response = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(TitleCollection.class); - assertEquals(STUB_MANAGED_TITLE_ID_2, response.getData().getFirst().getId()); - } - - @Test - public void shouldReturnTitlesOnSearchByAccessTypes() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.getFirst().getId(), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.getFirst().getId(), vertx); - - mockGetTitles(); - - String resourcePath = EHOLDINGS_TITLES_PATH + "?filter[access-type]=" + STUB_ACCESS_TYPE_NAME; - TitleCollection titleCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(TitleCollection.class); - List<TitleCollectionItem> titles = titleCollection.getData(); - - assertThat(titles, hasSize(2)); - assertEquals(2, (int) titleCollection.getMeta().getTotalResults()); - assertThat(titles, everyItem(hasProperty("id", - anyOf(equalTo(STUB_MANAGED_TITLE_ID), equalTo(STUB_MANAGED_TITLE_ID_2)) - ))); - } - - @Test - public void shouldReturnTitlesWithResourcesOnSearchByAccessTypes() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.getFirst().getId(), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.getFirst().getId(), vertx); - - mockGetTitles(); - - String resourcePath = - EHOLDINGS_TITLES_PATH + "?filter[access-type]=" + STUB_ACCESS_TYPE_NAME + "&include=resources"; - TitleCollection titleCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(TitleCollection.class); - List<TitleCollectionItem> titles = titleCollection.getData(); - - assertThat(titles, hasSize(2)); - assertEquals(2, (int) titleCollection.getMeta().getTotalResults()); - assertThat(titles, everyItem(hasProperty("id", - anyOf(equalTo(STUB_MANAGED_TITLE_ID), equalTo(STUB_MANAGED_TITLE_ID_2)) - ))); - assertThat(titles, everyItem(hasProperty("included", not(empty())))); - } - - @Test - public void shouldReturnTitleOnSearchByAccessTypesWithPagination() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.get(0).getId(), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.get(1).getId(), vertx); - - mockGetTitles(); - - String resourcePath = EHOLDINGS_TITLES_PATH + "?page=2&count=1&filter[access-type]=" + STUB_ACCESS_TYPE_NAME - + "&filter[access-type]=" + STUB_ACCESS_TYPE_NAME_2; - TitleCollection titleCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(TitleCollection.class); - List<TitleCollectionItem> titles = titleCollection.getData(); - - assertThat(titles, hasSize(1)); - assertEquals(2, (int) titleCollection.getMeta().getTotalResults()); - assertThat(titles, everyItem(hasProperty("id", equalTo(STUB_MANAGED_TITLE_ID)))); - } - - @Test - public void shouldReturnEmptyTitlesOnSearchByAccessTypesThatIsNotExist() throws IOException, URISyntaxException { - List<AccessType> accessTypes = insertAccessTypes(testData(configuration.getId()), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID, RESOURCE, accessTypes.get(0).getId(), vertx); - insertAccessTypeMapping(STUB_MANAGED_RESOURCE_ID_2, RESOURCE, accessTypes.get(1).getId(), vertx); - - mockGetTitles(); - - String resourcePath = EHOLDINGS_TITLES_PATH + "?filter[access-type]=Not Exist"; - TitleCollection titleCollection = getWithOk(resourcePath, STUB_USER_ID_HEADER).as(TitleCollection.class); - List<TitleCollectionItem> titles = titleCollection.getData(); - - assertThat(titles, hasSize(0)); - assertEquals(0, (int) titleCollection.getMeta().getTotalResults()); - } - - @Test - public void shouldReturnTitlesOnSearchByPackageIds() throws IOException, URISyntaxException, JSONException { - String stubResponseFile = "responses/rmapi/titles/searchTitles.json"; - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)))); - - String resourcePath = EHOLDINGS_TITLES_PATH + "?filter[packageIds]=1&filter[packageIds]=2&filter[packageIds]=3&" - + "filter[name]=Mind"; - String actualResponse = getWithOk(resourcePath, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals(readFile("responses/kb-ebsco/titles/expected-titles.json"), actualResponse, true); - } - - @Test - public void shouldReturn400ValidationErrorForPackageIds() { - - String resourcePath = EHOLDINGS_TITLES_PATH + "?filter[packageIds]=1&filter[packageIds]=abc&filter[name]=Mind"; - JsonapiError error = getWithStatus(resourcePath, SC_BAD_REQUEST, STUB_USER_ID_HEADER).as(JsonapiError.class); - assertErrorContainsTitle(error, "Invalid Query Parameter for filter[packageIds]"); - } - - @Test - public void shouldReturn400IfCountOutOfRange() { - JsonapiError error = - getWithStatus(EHOLDINGS_TITLES_PATH + "?count=1000&page=1&filter[name]=Mind&sort=name", SC_BAD_REQUEST, - STUB_USER_ID_HEADER).as(JsonapiError.class); - - assertErrorContainsTitle(error, "parameter value {1000} is not valid"); - } - - @Test - public void shouldReturn500WhenRmApiReturns500Error() { - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(500))); - - JsonapiError error = - getWithStatus(EHOLDINGS_TITLES_PATH + "?filter[name]=news", SC_INTERNAL_SERVER_ERROR, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid RMAPI response"); - } - - @Test - public void shouldReturnTitleWhenValidId() throws IOException, URISyntaxException, JSONException { - mockGetManagedTitleById(); - String actualResponse = getWithOk(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, STUB_USER_ID_HEADER).asString(); - JSONAssert.assertEquals( - readFile("responses/kb-ebsco/titles/expected-title-by-id.json"), actualResponse, false); - } - - @Test - public void shouldReturnTitleTagsWhenValidId() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/titles/get-title-by-id-response.json"; - saveTag(vertx, STUB_MANAGED_TITLE_ID, RecordType.TITLE, STUB_TAG_VALUE); - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)))); - - Title actualResponse = getWithOk(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, STUB_USER_ID_HEADER).as(Title.class); - - assertTrue(actualResponse.getData().getAttributes().getTags().getTagList().contains(STUB_TAG_VALUE)); - } - - @Test - public void shouldReturn404WhenRmApiNotFoundOnTitleGet() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/titles/get-title-by-id-not-found-response.json"; - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)) - .withStatus(404))); - - JsonapiError error = getWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, SC_NOT_FOUND, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Title not found"); - } - - @Test - public void shouldReturn400WhenValidationErrorOnTitleGet() { - JsonapiError error = getWithStatus(EHOLDINGS_TITLES_PATH + "/12345aaa", SC_BAD_REQUEST, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Title id is invalid - 12345aaa"); - } - - @Test - public void shouldReturn500WhenRmApiReturns500ErrorOnTitleGet() { - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(500))); - - JsonapiError error = - getWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, SC_INTERNAL_SERVER_ERROR, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Invalid RMAPI response"); - } - - @Test - public void shouldReturnTitleWithSortedResourcesWhenIncludeResources() - throws IOException, URISyntaxException, JSONException { - String rmapiResponseFile = "responses/rmapi/titles/get-title-by-id-response-with-resources.json"; - String rmapiUrl = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"; - - mockGet(new RegexPattern(rmapiUrl), rmapiResponseFile); - - String actual = getWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID + "?include=resources", SC_OK, - STUB_USER_ID_HEADER).asString(); - String expected = readFile("responses/kb-ebsco/titles/get-title-by-id-include-resources-response.json"); - - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturnTitleWithResourcesWhenIncludeResourcesWithTags() - throws IOException, URISyntaxException, JSONException { - saveTag(vertx, STUB_MANAGED_RESOURCE_ID, RecordType.RESOURCE, STUB_TAG_VALUE); - - String rmapiResponseFile = "responses/rmapi/titles/get-title-by-id-response.json"; - String rmapiUrl = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"; - - mockGet(new RegexPattern(rmapiUrl), rmapiResponseFile); - - String actual = getWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID + "?include=resources", SC_OK, - STUB_USER_ID_HEADER).asString(); - String expected = readFile("responses/kb-ebsco/titles/get-title-by-id-include-resources-with-tags-response.json"); - - JSONAssert.assertEquals(expected, actual, true); - } - - @Test - public void shouldReturnTitleWithoutResourcesWhenInvalidInclude() - throws IOException, URISyntaxException, JSONException { - String rmapiResponseFile = "responses/rmapi/titles/get-title-by-id-response.json"; - String rmapiUrl = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"; - - mockGet(new RegexPattern(rmapiUrl), rmapiResponseFile); - - String actual = getWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID + "?include=badValue", SC_OK, - STUB_USER_ID_HEADER).asString(); - String expected = readFile("responses/kb-ebsco/titles/get-title-by-id-invalid-include-response.json"); - - JSONAssert.assertEquals(expected, actual, false); - } - - @Test - public void shouldReturnTitleWhenValidPostRequest() throws IOException, URISyntaxException, JSONException { - String actual = postTitle(Collections.emptyList()).asString(); - String expected = readFile("responses/kb-ebsco/titles/get-created-title-response.json"); - - JSONAssert.assertEquals(expected, actual, false); - } - - @Test - public void shouldUpdateTagsWhenValidPostRequest() throws IOException, URISyntaxException { - List<String> tagList = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); - Title actual = postTitle(tagList).as(Title.class); - List<String> tagsFromDb = TagsTestUtil.getTags(vertx); - assertThat(actual.getData().getAttributes().getTags().getTagList(), containsInAnyOrder(tagList.toArray())); - assertThat(tagsFromDb, containsInAnyOrder(tagList.toArray())); - } - - @Test - public void shouldAddTitleDataOnPost() throws URISyntaxException, IOException { - postTitle(Collections.singletonList(STUB_TAG_VALUE)); - List<DbTitle> titles = TitlesTestUtil.getTitles(vertx); - assertEquals(1, titles.size()); - assertEquals(STUB_TITLE_ID, String.valueOf(titles.getFirst().getId())); - assertEquals("Test Title", titles.getFirst().getName()); - } - - @Test - public void shouldReturn400WhenInvalidPostRequest() throws URISyntaxException, IOException { - String errorResponse = "responses/rmapi/packages/post-package-400-error-response.json"; - String titlePostStubRequestFile = "requests/kb-ebsco/title/post-title-request.json"; - - stubFor(post(urlPathEqualTo("/rm/rmaccounts/%s/vendors/%s/packages/%s/titles" - .formatted(STUB_CUSTOMER_ID, STUB_VENDOR_ID, STUB_PACKAGE_ID))) - .willReturn(new ResponseDefinitionBuilder().withBody(readFile(errorResponse)).withStatus(SC_BAD_REQUEST))); - - var error = - postWithStatus(EHOLDINGS_TITLES_PATH, readFile(titlePostStubRequestFile), SC_BAD_REQUEST, STUB_USER_ID_HEADER) - .as(JsonapiError.class); - - assertErrorContainsTitle(error, "Package with the provided name already exists"); - } - - @Test - public void shouldReturnUpdatedValuesForCustomTitleOnSuccessfulPut() - throws IOException, URISyntaxException, JSONException { - String expectedTitleFile = "responses/kb-ebsco/titles/expected-updated-title.json"; - String actualResponse = putTitle(null); - - JSONAssert.assertEquals(readFile(expectedTitleFile), actualResponse, false); - - verify(1, putRequestedFor(new UrlPathPattern(new RegexPattern(CUSTOM_RESOURCE_ENDPOINT), true)) - .withRequestBody( - equalToJson(readFile("requests/rmapi/resources/put-custom-resource-is-selected-multiple-attributes.json")))); - } - - @Test - public void shouldUpdateTitleTagsOnSuccessfulPut() throws IOException, URISyntaxException { - List<String> newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); - - putTitle(newTags); - - List<String> tags = TagsTestUtil.getTags(vertx); - assertThat(tags, containsInAnyOrder(newTags.toArray())); - } - - @Test - public void shouldUpdateOnlyTagsOnPutForNonCustomTitle() throws IOException, URISyntaxException { - String resourceResponse = "responses/rmapi/resources/get-managed-resource-updated-response.json"; - ObjectMapper mapper = new ObjectMapper(); - TitlePutRequest request = mapper.readValue(readFile("requests/kb-ebsco/title/put-title.json"), - TitlePutRequest.class); - List<String> newTags = Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2); - request.getData().getAttributes().setTags(new Tags().withTagList(newTags)); - - stubFor(get(new UrlPathPattern(new RegexPattern(CUSTOM_TITLE_ENDPOINT), false)).willReturn( - new ResponseDefinitionBuilder().withBody(readFile(resourceResponse)))); - - putWithOk(EHOLDINGS_TITLES_PATH + "/" + STUB_CUSTOM_TITLE_ID, mapper.writeValueAsString(request), - STUB_USER_ID_HEADER); - - List<String> tags = TagsTestUtil.getTags(vertx); - assertThat(tags, containsInAnyOrder(newTags.toArray())); - WireMock.verify(0, putRequestedFor(anyUrl())); - } - - @Test - public void shouldAddTitleDataOnPut() throws IOException, URISyntaxException { - putTitle(Arrays.asList(STUB_TAG_VALUE, STUB_TAG_VALUE_2)); - - List<DbTitle> titles = TitlesTestUtil.getTitles(vertx); - assertEquals(1, titles.size()); - assertEqualsLong(titles.getFirst().getId()); - assertEquals("sd-test-java-again", titles.getFirst().getName()); - } - - @Test - public void shouldDeleteTitleDataOnPutWithEmptyTagList() throws IOException, URISyntaxException { - putTitle(Collections.singletonList(STUB_TAG_VALUE)); - putTitle(Collections.emptyList()); - - List<DbTitle> packages = TitlesTestUtil.getTitles(vertx); - assertThat(packages, is(empty())); - } - - @Test - public void shouldUpdateTitleDataOnSecondPut() throws IOException, URISyntaxException { - String newName = "new name"; - String updatedResponse = "responses/rmapi/resources/get-custom-resource-updated-title-name-response.json"; - - putTitle(readFile(updatedResponse), Collections.singletonList(STUB_TAG_VALUE)); - - ObjectMapper mapper = new ObjectMapper(); - TitlePutRequest request = mapper.readValue(readFile("requests/kb-ebsco/title/put-title.json"), - TitlePutRequest.class); - request.getData().getAttributes().withName(newName); - - stubFor(get(new UrlPathPattern(new RegexPattern(CUSTOM_TITLE_ENDPOINT), false)).willReturn( - new ResponseDefinitionBuilder().withBody(readFile(updatedResponse)))); - - putWithOk(EHOLDINGS_TITLES_PATH + "/" + STUB_CUSTOM_TITLE_ID, mapper.writeValueAsString(request), - STUB_USER_ID_HEADER); - - List<DbTitle> titles = TitlesTestUtil.getTitles(vertx); - assertEquals(1, titles.size()); - assertEqualsLong(titles.getFirst().getId()); - assertEquals(newName, titles.getFirst().getName()); - } - - @Test - public void shouldReturn422WhenNameIsNotProvided() throws URISyntaxException, IOException { - Errors error = putWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, - readFile("requests/kb-ebsco/title/put-title-null-name.json"), SC_UNPROCESSABLE_ENTITY, STUB_USER_ID_HEADER) - .as(Errors.class); - - assertThat(error.getErrors().getFirst().getMessage(), containsString("must not be null")); - } - - private String putTitle(List<String> tags) throws IOException, URISyntaxException { - String updatedResourceResponse = "responses/rmapi/resources/get-custom-resource-updated-response.json"; - return putTitle(readFile(updatedResourceResponse), tags); - } - - private String putTitle(String updatedResourceResponse, List<String> tags) throws IOException, URISyntaxException { - stubFor( - get(new UrlPathPattern(new RegexPattern(CUSTOM_TITLE_ENDPOINT), false)) - .willReturn(new ResponseDefinitionBuilder().withBody(updatedResourceResponse))); - - stubFor( - put(new UrlPathPattern(new RegexPattern(CUSTOM_RESOURCE_ENDPOINT), true)) - .willReturn(new ResponseDefinitionBuilder().withStatus(SC_NO_CONTENT))); - - ObjectMapper mapper = new ObjectMapper(); - TitlePutRequest titleToBeUpdated = - mapper.readValue(readFile("requests/kb-ebsco/title/put-title.json"), TitlePutRequest.class); - - if (tags != null) { - titleToBeUpdated.getData().getAttributes().setTags(new Tags() - .withTagList(tags)); - } - - return putWithOk(EHOLDINGS_TITLES_PATH + "/" + STUB_CUSTOM_TITLE_ID, mapper.writeValueAsString(titleToBeUpdated), - STUB_USER_ID_HEADER).asString(); - } - - private ExtractableResponse<Response> postTitle(List<String> tags) throws IOException, URISyntaxException { - String titleCreatedIdStubResponseFile = "responses/rmapi/titles/post-title-response.json"; - String titlePostStubRequestFile = "requests/kb-ebsco/title/post-title-request.json"; - String getTitleByTitleIdStubFile = "responses/rmapi/titles/get-title-by-id-for-post-request.json"; - - stubFor( - post(new UrlPathPattern(new EqualToPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" - + STUB_VENDOR_ID + "/packages/" + STUB_PACKAGE_ID + "/titles"), false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(titleCreatedIdStubResponseFile)) - .withStatus(SC_OK))); - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_TITLE_ID), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(getTitleByTitleIdStubFile)) - .withStatus(SC_OK))); - - ObjectMapper mapper = new ObjectMapper(); - TitlePostRequest request = mapper.readValue(readFile(titlePostStubRequestFile), TitlePostRequest.class); - request.getData().getAttributes().setTags(new Tags().withTagList(tags)); - - return postWithOk(EHOLDINGS_TITLES_PATH, mapper.writeValueAsString(request), STUB_USER_ID_HEADER); - } - - private void mockGetManagedTitleById() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/titles/get-title-by-id-response.json"; - - stubFor( - get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles.*"), true)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(readFile(stubResponseFile)))); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/LoadHoldingsStatusImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/LoadHoldingsStatusImplTest.java deleted file mode 100644 index c5c3b247d..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/LoadHoldingsStatusImplTest.java +++ /dev/null @@ -1,208 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static java.time.ZonedDateTime.parse; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.RmApiConstants.RMAPI_HOLDINGS_STATUS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_POST_HOLDINGS_URL; -import static org.folio.rest.impl.integrationsuite.DefaultLoadHoldingsImplTest.HOLDINGS_LOAD_BY_ID_URL; -import static org.folio.rest.impl.integrationsuite.DefaultLoadHoldingsImplTest.handleStatusChange; -import static org.folio.rest.jaxrs.model.LoadStatusNameEnum.COMPLETED; -import static org.folio.rest.jaxrs.model.LoadStatusNameEnum.FAILED; -import static org.folio.rest.util.DateTimeUtil.POSTGRES_TIMESTAMP_FORMATTER; -import static org.folio.service.holdings.HoldingConstants.CREATE_SNAPSHOT_ACTION; -import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.LOAD_FACADE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.mockResponseList; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; -import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.interceptAndContinue; -import static org.folio.util.KbTestUtil.interceptAndStop; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertTrue; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.core.Handler; -import io.vertx.core.eventbus.DeliveryContext; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import org.folio.repository.holdings.status.HoldingsStatusRepositoryImpl; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.HoldingsLoadingStatus; -import org.folio.rest.jaxrs.model.JsonapiError; -import org.folio.rest.jaxrs.model.LoadStatusData; -import org.folio.rest.jaxrs.model.LoadStatusNameDetailEnum; -import org.folio.rest.jaxrs.model.LoadStatusNameEnum; -import org.folio.service.holdings.HoldingsService; -import org.folio.service.holdings.message.LoadHoldingsMessage; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; -import org.springframework.beans.factory.annotation.Autowired; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class LoadHoldingsStatusImplTest extends WireMockTestBase { - - private static final String HOLDINGS_LOAD_STATUS_BY_ID_URL = "/eholdings/loading/kb-credentials/%s/status"; - private static final String STUB_HOLDINGS_LOAD_STATUS_BY_ID_URL = - String.format(HOLDINGS_LOAD_STATUS_BY_ID_URL, STUB_CREDENTIALS_ID); - private static final int TIMEOUT = 300; - private static final int SNAPSHOT_RETRIES = 2; - - @InjectMocks - @Autowired - public HoldingsService holdingsService; - @Spy - @Autowired - public HoldingsStatusRepositoryImpl holdingsStatusRepository; - - private final List<Handler<DeliveryContext<LoadHoldingsMessage>>> interceptors = new ArrayList<>(); - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - MockitoAnnotations.openMocks(this).close(); - } - - @After - public void tearDown() { - interceptors.forEach(interceptor -> vertx.eventBus().removeOutboundInterceptor(interceptor)); - - tearDownHoldingsData(); - } - - @Test - public void shouldReturnStatusNotStarted() { - setupDefaultLoadKbConfiguration(); - final HoldingsLoadingStatus status = - getWithOk(STUB_HOLDINGS_LOAD_STATUS_BY_ID_URL, STUB_USER_ID_HEADER).body().as(HoldingsLoadingStatus.class); - assertThat(status.getData().getAttributes().getStatus().getName(), equalTo(LoadStatusNameEnum.NOT_STARTED)); - } - - @Test - public void shouldReturnStatusPopulatingStagingArea(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - mockResponseList(new UrlPathPattern(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), false), - new ResponseDefinitionBuilder().withBody(readFile("responses/rmapi/holdings/status/get-status-in-progress.json")) - .withStatus(200), - new ResponseDefinitionBuilder().withBody(readFile("responses/rmapi/holdings/status/get-status-completed.json")) - .withStatus(200)); - - Async startedAsync = context.async(); - Handler<DeliveryContext<LoadHoldingsMessage>> interceptor = - interceptAndContinue(LOAD_FACADE_ADDRESS, CREATE_SNAPSHOT_ACTION, message -> startedAsync.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - interceptors.add(interceptor); - - Async finishedAsync = context.async(); - interceptor = - interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> finishedAsync.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - interceptors.add(interceptor); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - startedAsync.await(TIMEOUT); - - final HoldingsLoadingStatus status = - getWithOk(STUB_HOLDINGS_LOAD_STATUS_BY_ID_URL, STUB_USER_ID_HEADER).body().as(HoldingsLoadingStatus.class); - assertThat(status.getData().getAttributes().getStatus().getDetail(), - equalTo(LoadStatusNameDetailEnum.POPULATING_STAGING_AREA)); - - finishedAsync.await(TIMEOUT); - } - - @Test - public void shouldReturnStatusCompleted(TestContext context) throws IOException, URISyntaxException { - setupDefaultLoadKbConfiguration(); - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), - "responses/rmapi/holdings/status/get-status-completed-one-page.json"); - - stubFor(post(new UrlPathPattern(new EqualToPattern(RMAPI_POST_HOLDINGS_URL), false)).willReturn( - new ResponseDefinitionBuilder().withBody("").withStatus(202))); - - mockGet(new RegexPattern(RMAPI_POST_HOLDINGS_URL), "responses/rmapi/holdings/holdings/get-holdings.json"); - - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - async.await(TIMEOUT); - final HoldingsLoadingStatus status = - getWithOk(STUB_HOLDINGS_LOAD_STATUS_BY_ID_URL, STUB_USER_ID_HEADER).body().as(HoldingsLoadingStatus.class); - - assertThat(status.getData().getType(), equalTo(LoadStatusData.Type.STATUS)); - assertThat(status.getData().getAttributes().getTotalCount(), equalTo(2)); - assertThat(status.getData().getAttributes().getStatus().getName(), equalTo(COMPLETED)); - - assertTrue(parse(status.getData().getAttributes().getStarted(), POSTGRES_TIMESTAMP_FORMATTER).isBefore( - parse(status.getData().getAttributes().getFinished(), POSTGRES_TIMESTAMP_FORMATTER))); - } - - @Test - public void shouldReturnErrorWhenRmApiReturnsError(TestContext context) { - setupDefaultLoadKbConfiguration(); - mockGet(new EqualToPattern(RMAPI_HOLDINGS_STATUS_URL), SC_INTERNAL_SERVER_ERROR); - - Async finishedAsync = context.async(SNAPSHOT_RETRIES); - handleStatusChange(FAILED, holdingsStatusRepository, o -> finishedAsync.countDown()); - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - finishedAsync.await(TIMEOUT); - - final HoldingsLoadingStatus status = - getWithOk(STUB_HOLDINGS_LOAD_STATUS_BY_ID_URL, STUB_USER_ID_HEADER).body().as(HoldingsLoadingStatus.class); - assertThat(status.getData().getAttributes().getStatus().getName(), equalTo(FAILED)); - } - - @Test - public void shouldReturn404WhenNoKbCredentialsFound() { - final String url = String.format(HOLDINGS_LOAD_STATUS_BY_ID_URL, UUID.randomUUID()); - final JsonapiError error = getWithStatus(url, SC_NOT_FOUND, JOHN_USER_ID_HEADER).as(JsonapiError.class); - assertThat(error.getErrors().getFirst().getTitle(), containsString("not exist")); - } - - @Test - public void shouldReturn401WhenNoHeader() { - final String url = String.format(HOLDINGS_LOAD_STATUS_BY_ID_URL, UUID.randomUUID()); - final JsonapiError error = getWithStatus(url, SC_UNAUTHORIZED).as(JsonapiError.class); - assertThat(error.getErrors().getFirst().getTitle(), containsString("X-Okapi-User-Id header is required")); - } - - public void setupDefaultLoadKbConfiguration() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); - insertRetryStatus(STUB_CREDENTIALS_ID, vertx); - } - - private void tearDownHoldingsData() { - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadHoldingsImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadHoldingsImplTest.java deleted file mode 100644 index 687109b15..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadHoldingsImplTest.java +++ /dev/null @@ -1,449 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.RmApiConstants.RMAPI_DELTAS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_DELTA_BY_ID_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_DELTA_STATUS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_POST_TRANSACTIONS_HOLDINGS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_TRANSACTIONS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_TRANSACTION_BY_ID_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_TRANSACTION_STATUS_URL; -import static org.folio.rest.impl.integrationsuite.DefaultLoadHoldingsImplTest.HOLDINGS_LOAD_BY_ID_URL; -import static org.folio.rest.jaxrs.model.LoadStatusNameEnum.COMPLETED; -import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.LOAD_FACADE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.SAVE_HOLDINGS_ACTION; -import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; -import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_FAILED_ACTION; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGet; -import static org.folio.test.util.TestUtil.mockGetWithBody; -import static org.folio.test.util.TestUtil.mockResponseList; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; -import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; -import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID_HEADER; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.interceptAndContinue; -import static org.folio.util.KbTestUtil.interceptAndStop; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.doAnswer; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.http.RequestMethod; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; -import com.github.tomakehurst.wiremock.matching.StringValuePattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.core.Handler; -import io.vertx.core.eventbus.DeliveryContext; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.HoldingsDownloadTransaction; -import org.folio.holdingsiq.model.HoldingsTransactionIdsList; -import org.folio.holdingsiq.model.TransactionId; -import org.folio.repository.holdings.DbHoldingInfo; -import org.folio.repository.holdings.status.HoldingsStatusRepositoryImpl; -import org.folio.repository.holdings.status.retry.RetryStatusRepository; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.rest.jaxrs.model.LoadStatusNameEnum; -import org.folio.service.holdings.HoldingsService; -import org.folio.service.holdings.LoadServiceFacade; -import org.folio.service.holdings.message.HoldingsMessage; -import org.folio.service.holdings.message.LoadHoldingsMessage; -import org.folio.util.HoldingsTestUtil; -import org.folio.util.TransactionIdTestUtil; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; -import org.springframework.beans.factory.annotation.Autowired; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class TransactionLoadHoldingsImplTest extends WireMockTestBase { - - private static final String PREVIOUS_TRANSACTION_ID = "abcd3ab0-da4b-4a1f-a004-a9d323e54cde"; - private static final String TRANSACTION_ID = "84113ab0-da4b-4a1f-a004-a9d686e54811"; - private static final String DELTA_ID = "7e3537a0-3f30-4ef8-9470-dd0a87ac1066"; - private static final String DELETED_HOLDING_ID = "123356-3157070-19412030"; - private static final String UPDATED_HOLDING_ID = "123357-3157072-19412032"; - private static final String ADDED_HOLDING_ID = "36-7191-2435667"; - private static final int TIMEOUT = 60000; - private static final int EXPECTED_LOADED_PAGES = 2; - private static final int TEST_SNAPSHOT_RETRY_COUNT = 2; - private static final String STUB_HOLDINGS_TITLE = "java-test-one"; - private static final String RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED = - "responses/rmapi/holdings/status/get-transaction-status-completed.json"; - private static final String RMAPI_RESPONSE_HOLDINGS = "responses/rmapi/holdings/holdings/get-holdings.json"; - - @InjectMocks - @Autowired - HoldingsService holdingsService; - @Spy - @Autowired - HoldingsStatusRepositoryImpl holdingsStatusRepository; - @Autowired - RetryStatusRepository retryStatusRepository; - private Configuration configuration; - private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; - - @BeforeClass - public static void setUpClass(TestContext context) { - System.setProperty("holdings.load.implementation.qualifier", "transactionLoadServiceFacade"); - WireMockTestBase.setUpClass(context); - } - - @AfterClass - public static void tearDownPropertiesAfterClass() { - System.clearProperty("holdings.load.implementation.qualifier"); - } - - public static void handleStatusChange(LoadStatusNameEnum status, HoldingsStatusRepositoryImpl repositorySpy, - Consumer<Void> handler) { - doAnswer(invocationOnMock -> { - @SuppressWarnings("unchecked") - CompletableFuture<Void> future = (CompletableFuture<Void>) invocationOnMock.callRealMethod(); - return future.thenAccept(handler); - }).when(repositorySpy).update( - argThat(argument -> argument.getData().getAttributes().getStatus().getName() == status), any(UUID.class), - anyString()); - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - MockitoAnnotations.openMocks(this).close(); - configuration = Configuration.builder() - .apiKey(STUB_API_KEY) - .customerId(STUB_CUSTOMER_ID) - .url(getWiremockUrl()) - .build(); - setupDefaultLoadKbConfiguration(); - } - - @After - public void tearDown() { - if (interceptor != null) { - vertx.eventBus().removeOutboundInterceptor(interceptor); - } - tearDownHoldingsData(); - } - - @Test - public void shouldSaveHoldings(TestContext context) throws IOException, URISyntaxException { - - runPostHoldingsWithMocks(context); - - final List<DbHoldingInfo> holdingsList = HoldingsTestUtil.getHoldings(vertx); - assertThat(holdingsList.size(), Matchers.notNullValue()); - } - - @Test - public void shouldSaveHoldingsWhenPreviousTransactionExpired(TestContext context) - throws IOException, URISyntaxException { - - TransactionIdTestUtil.addTransactionId(STUB_CREDENTIALS_ID, PREVIOUS_TRANSACTION_ID, vertx); - runPostHoldingsWithMocks(context); - - final List<DbHoldingInfo> holdingsList = HoldingsTestUtil.getHoldings(vertx); - assertThat(holdingsList.size(), Matchers.notNullValue()); - } - - @Test - @SuppressWarnings("checkstyle:MethodLength") - public void shouldUpdateHoldingsWithDeltas(TestContext context) throws IOException, URISyntaxException { - HoldingsTestUtil.saveHolding(STUB_CREDENTIALS_ID, - Json.decodeValue(readFile("responses/kb-ebsco/holdings/custom-holding.json"), DbHoldingInfo.class), - OffsetDateTime.now(), vertx); - HoldingsTestUtil.saveHolding(STUB_CREDENTIALS_ID, - Json.decodeValue(readFile("responses/kb-ebsco/holdings/custom-holding2.json"), DbHoldingInfo.class), - OffsetDateTime.now(), vertx); - TransactionIdTestUtil.addTransactionId(STUB_CREDENTIALS_ID, PREVIOUS_TRANSACTION_ID, vertx); - - HoldingsDownloadTransaction previousTransaction = HoldingsDownloadTransaction.builder() - .creationDate(OffsetDateTime.now().minusHours(500).toString()) - .transactionId(PREVIOUS_TRANSACTION_ID) - .build(); - mockTransactionList(Collections.singletonList(previousTransaction)); - mockPostHoldings(); - mockGet(new EqualToPattern(getStatusEndpoint(PREVIOUS_TRANSACTION_ID)), - RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED); - mockGet(new EqualToPattern(getStatusEndpoint(TRANSACTION_ID)), RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED); - mockPostDeltaReport(); - mockGet(new EqualToPattern(getDeltaReportStatusEndpoint()), - "responses/rmapi/holdings/status/get-delta-report-status-completed.json"); - mockGet(new EqualToPattern(getDeltaEndpoint()), "responses/rmapi/holdings/delta/get-delta.json"); - - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - - Map<String, DbHoldingInfo> holdings = HoldingsTestUtil.getHoldings(vertx) - .stream() - .collect(Collectors.toMap(this::getHoldingsId, Function.identity())); - - assertFalse(holdings.containsKey(DELETED_HOLDING_ID)); - - DbHoldingInfo updatedHolding = holdings.get(UPDATED_HOLDING_ID); - assertEquals("Test Title Updated", updatedHolding.getPublicationTitle()); - assertEquals("Test one Press Updated", updatedHolding.getPublisherName()); - assertEquals("Book", updatedHolding.getResourceType()); - - DbHoldingInfo addedHolding = holdings.get(ADDED_HOLDING_ID); - assertEquals("Added test title", addedHolding.getPublicationTitle()); - assertEquals("Added test publisher", addedHolding.getPublisherName()); - assertEquals("Book", addedHolding.getResourceType()); - } - - @Test - public void shouldRetryCreationOfSnapshotWhenItFails(TestContext context) throws IOException, URISyntaxException { - mockEmptyTransactionList(); - - stubFor( - post(new UrlPathPattern(new EqualToPattern(RMAPI_POST_TRANSACTIONS_HOLDINGS_URL), false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(Json.encode(createTransactionId())) - .withStatus(202))); - ResponseDefinitionBuilder failedResponse = new ResponseDefinitionBuilder().withStatus(500); - ResponseDefinitionBuilder successfulResponse = new ResponseDefinitionBuilder() - .withBody(readFile(RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED)); - mockResponseList(new UrlPathPattern(new EqualToPattern(getStatusEndpoint()), false), - failedResponse, - successfulResponse, - successfulResponse); - - Async async = context.async(); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, message -> async.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - public void shouldStopRetryingAfterMultipleFailures(TestContext context) throws IOException, URISyntaxException { - mockEmptyTransactionList(); - mockGet(new EqualToPattern(getStatusEndpoint()), RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED); - - UrlPathPattern urlPattern = new UrlPathPattern(new EqualToPattern(RMAPI_POST_TRANSACTIONS_HOLDINGS_URL), false); - stubFor( - post(urlPattern) - .willReturn(new ResponseDefinitionBuilder() - .withStatus(500))); - - Async async = context.async(TEST_SNAPSHOT_RETRY_COUNT); - interceptor = interceptAndContinue(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_FAILED_ACTION, o -> async.countDown()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - - Async retryStatusAsync = context.async(); - retryStatusRepository.findByCredentialsId(UUID.fromString(STUB_CREDENTIALS_ID), STUB_TENANT) - .thenAccept(status -> { - boolean timerExists = vertx.cancelTimer(status.getTimerId()); - context.assertEquals(0, status.getRetryAttemptsLeft()); - context.assertFalse(timerExists); - retryStatusAsync.complete(); - }); - retryStatusAsync.await(TIMEOUT); - - verify(TEST_SNAPSHOT_RETRY_COUNT, - RequestPatternBuilder.newRequestPattern(RequestMethod.POST, urlPattern)); - } - - @Test - public void shouldRetryLoadingHoldingsFromStartWhenPageFailsToLoad(TestContext context) - throws IOException, URISyntaxException { - mockEmptyTransactionList(); - mockGet(new EqualToPattern(getStatusEndpoint()), RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED); - - stubFor(post(urlPathEqualTo(RMAPI_POST_TRANSACTIONS_HOLDINGS_URL)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(Json.encode(createTransactionId())) - .withStatus(202))); - - ResponseDefinitionBuilder successResponse = new ResponseDefinitionBuilder() - .withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) - .withStatus(200); - ResponseDefinitionBuilder failResponse = new ResponseDefinitionBuilder().withStatus(500); - mockResponseList(urlPathEqualTo(getHoldingsEndpoint()), - successResponse, failResponse, failResponse, successResponse); - - int firstTryPages = 1; - int secondTryPages = 2; - Async async = context.async(firstTryPages + secondTryPages); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, message -> async.countDown()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - public void shouldSendSaveHoldingsEventForEachLoadedPage(TestContext context) throws IOException, URISyntaxException { - mockEmptyTransactionList(); - mockGet(new EqualToPattern(getStatusEndpoint()), RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED); - mockGet(new RegexPattern(getHoldingsEndpoint()), RMAPI_RESPONSE_HOLDINGS); - - List<HoldingsMessage> messages = new ArrayList<>(); - Async async = context.async(EXPECTED_LOADED_PAGES); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SAVE_HOLDINGS_ACTION, - message -> { - messages.add(((JsonObject) message.body()).getJsonObject("holdings").mapTo(HoldingsMessage.class)); - async.countDown(); - }); - vertx.eventBus().addOutboundInterceptor(interceptor); - - LoadServiceFacade proxy = LoadServiceFacade.createProxy(vertx, LOAD_FACADE_ADDRESS); - LoadHoldingsMessage message = new LoadHoldingsMessage(this.configuration, STUB_CREDENTIALS_ID, - STUB_TENANT, 5001, 2, TRANSACTION_ID, null); - proxy.loadHoldings(message); - - async.await(TIMEOUT); - assertEquals(2, messages.size()); - assertEquals(STUB_HOLDINGS_TITLE, messages.getFirst().getHoldingList().getFirst().getPublicationTitle()); - } - - @Test - public void shouldRetryLoadingPageWhenPageFails(TestContext context) throws IOException, URISyntaxException { - mockEmptyTransactionList(); - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - mockGet(new EqualToPattern(getStatusEndpoint()), - "responses/rmapi/holdings/status/get-transaction-status-completed-one-page.json"); - - mockPostHoldings(); - mockResponseList(new UrlPathPattern(new EqualToPattern(getHoldingsEndpoint()), false), - new ResponseDefinitionBuilder().withStatus(SC_INTERNAL_SERVER_ERROR), - new ResponseDefinitionBuilder().withBody(readFile(RMAPI_RESPONSE_HOLDINGS)) - ); - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - public void setupDefaultLoadKbConfiguration() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); - insertRetryStatus(STUB_CREDENTIALS_ID, vertx); - } - - private void runPostHoldingsWithMocks(TestContext context) throws IOException, URISyntaxException { - Async async = context.async(); - handleStatusChange(COMPLETED, holdingsStatusRepository, o -> async.complete()); - - mockEmptyTransactionList(); - mockGet(new EqualToPattern(getStatusEndpoint()), RMAPI_RESPONSE_TRANSACTION_STATUS_COMPLETED); - mockPostHoldings(); - mockGet(new RegexPattern(getHoldingsEndpoint()), RMAPI_RESPONSE_HOLDINGS); - - postWithStatus(HOLDINGS_LOAD_BY_ID_URL, "", SC_NO_CONTENT, STUB_USER_ID_HEADER); - - async.await(TIMEOUT); - } - - private void mockEmptyTransactionList() { - mockTransactionList(Collections.emptyList()); - } - - private void mockTransactionList(List<HoldingsDownloadTransaction> transactionIds) { - HoldingsTransactionIdsList emptyTransactionList = - HoldingsTransactionIdsList.builder().holdingsDownloadTransactionIds(transactionIds).build(); - mockGetWithBody(new EqualToPattern(RMAPI_TRANSACTIONS_URL), Json.encode(emptyTransactionList)); - } - - private String getHoldingsEndpoint() { - return String.format(RMAPI_TRANSACTION_BY_ID_URL, TRANSACTION_ID); - } - - private String getDeltaEndpoint() { - return String.format(RMAPI_DELTA_BY_ID_URL, DELTA_ID); - } - - private void mockPostHoldings() { - StringValuePattern urlPattern = new EqualToPattern(RMAPI_POST_TRANSACTIONS_HOLDINGS_URL); - stubFor(post(new UrlPathPattern(urlPattern, false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(Json.encode(createTransactionId())) - .withStatus(202))); - } - - private void mockPostDeltaReport() { - StringValuePattern urlPattern = new EqualToPattern(RMAPI_DELTAS_URL); - stubFor(post(new UrlPathPattern(urlPattern, false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(DELTA_ID) - .withStatus(202))); - } - - private TransactionId createTransactionId() { - return TransactionId.builder().transactionId(TRANSACTION_ID).build(); - } - - private String getStatusEndpoint() { - return getStatusEndpoint(TRANSACTION_ID); - } - - private String getStatusEndpoint(String id) { - return String.format(RMAPI_TRANSACTION_STATUS_URL, id); - } - - private String getDeltaReportStatusEndpoint() { - return String.format(RMAPI_DELTA_STATUS_URL, DELTA_ID); - } - - private String getHoldingsId(DbHoldingInfo holding) { - return holding.getVendorId() + "-" + holding.getPackageId() + "-" + holding.getTitleId(); - } - - private void tearDownHoldingsData() { - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadServiceFacadeTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadServiceFacadeTest.java deleted file mode 100644 index 310ecff00..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadServiceFacadeTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.folio.rest.impl.integrationsuite; - -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; -import static org.folio.rest.impl.RmApiConstants.RMAPI_POST_TRANSACTIONS_HOLDINGS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_TRANSACTIONS_URL; -import static org.folio.rest.impl.RmApiConstants.RMAPI_TRANSACTION_STATUS_URL; -import static org.folio.service.holdings.AbstractLoadServiceFacade.HOLDINGS_STATUS_TIME_FORMATTER; -import static org.folio.service.holdings.HoldingConstants.HOLDINGS_SERVICE_ADDRESS; -import static org.folio.service.holdings.HoldingConstants.SNAPSHOT_CREATED_ACTION; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGetWithBody; -import static org.folio.test.util.TestUtil.mockResponseList; -import static org.folio.test.util.TestUtil.readFile; -import static org.folio.test.util.TestUtil.readJsonFile; -import static org.folio.util.HoldingsRetryStatusTestUtil.insertRetryStatus; -import static org.folio.util.HoldingsStatusUtil.saveStatusNotStarted; -import static org.folio.util.KbCredentialsTestUtil.saveKbCredentials; -import static org.folio.util.KbTestUtil.clearDataFromTable; -import static org.folio.util.KbTestUtil.interceptAndStop; -import static org.junit.Assert.assertTrue; - -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.matching.EqualToPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; -import io.vertx.core.Handler; -import io.vertx.core.eventbus.DeliveryContext; -import io.vertx.core.json.Json; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.Collections; -import org.folio.holdingsiq.model.Configuration; -import org.folio.holdingsiq.model.HoldingsDownloadTransaction; -import org.folio.holdingsiq.model.HoldingsLoadTransactionStatus; -import org.folio.holdingsiq.model.HoldingsTransactionIdsList; -import org.folio.holdingsiq.model.TransactionId; -import org.folio.rest.impl.WireMockTestBase; -import org.folio.service.holdings.TransactionLoadServiceFacade; -import org.folio.service.holdings.message.ConfigurationMessage; -import org.folio.service.holdings.message.LoadHoldingsMessage; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; - -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class TransactionLoadServiceFacadeTest extends WireMockTestBase { - - private static final String TRANSACTION_ID = "84113ab0-da4b-4a1f-a004-a9d686e54811"; - private static final int TIMEOUT = 60000; - - @Autowired - TransactionLoadServiceFacade loadServiceFacade; - - private Configuration stubConfiguration; - - private Handler<DeliveryContext<LoadHoldingsMessage>> interceptor; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - stubConfiguration = Configuration.builder() - .apiKey(STUB_API_KEY) - .customerId(STUB_CUSTOMER_ID) - .url(getWiremockUrl()) - .build(); - setupDefaultLoadKbConfiguration(); - } - - @After - public void tearDown() { - if (interceptor != null) { - vertx.eventBus().removeOutboundInterceptor(interceptor); - } - tearDownHoldingsData(); - } - - @Test - public void shouldCreateSnapshotOnInitialStatusNone(TestContext context) throws IOException, URISyntaxException { - - mockEmptyTransactionList(); - - mockResponseList(new UrlPathPattern(new EqualToPattern(getStatusEndpoint()), false), - new ResponseDefinitionBuilder().withBody( - readFile("responses/rmapi/holdings/status/get-transaction-status-completed.json")) - ); - mockPostHoldings(); - - Async async = context.async(); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, - message -> async.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - loadServiceFacade.createSnapshot(new ConfigurationMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT)); - - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - public void shouldCreateSnapshotUsingExistingTransactionIfItIsInProgress(TestContext context) - throws IOException, URISyntaxException { - - mockGetWithBody(new EqualToPattern(RMAPI_TRANSACTIONS_URL), - readFile("responses/rmapi/holdings/status/get-transaction-list-in-progress.json")); - - mockResponseList(new UrlPathPattern(new EqualToPattern(getStatusEndpoint()), false), - new ResponseDefinitionBuilder().withBody( - readFile("responses/rmapi/holdings/status/get-transaction-status-completed.json")) - ); - mockPostHoldings(); - - Async async = context.async(); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, - message -> async.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - loadServiceFacade.createSnapshot(new ConfigurationMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT)); - - async.await(TIMEOUT); - assertTrue(async.isSucceeded()); - } - - @Test - public void shouldNotCreateSnapshotIfItWasRecentlyCreated(TestContext context) - throws IOException, URISyntaxException { - - String now = HOLDINGS_STATUS_TIME_FORMATTER.format(LocalDateTime.now(ZoneOffset.UTC)); - HoldingsTransactionIdsList idList = - readJsonFile("responses/rmapi/holdings/status/get-transaction-list.json", HoldingsTransactionIdsList.class); - HoldingsDownloadTransaction firstTransaction = idList.getHoldingsDownloadTransactionIds().getFirst(); - idList.getHoldingsDownloadTransactionIds().set(0, firstTransaction.toBuilder().creationDate(now).build()); - HoldingsLoadTransactionStatus status = - readJsonFile("responses/rmapi/holdings/status/get-transaction-status-completed.json", - HoldingsLoadTransactionStatus.class) - .toBuilder().creationDate(now).build(); - mockGetWithBody(new EqualToPattern(RMAPI_TRANSACTIONS_URL), Json.encode(idList)); - mockGetWithBody(new EqualToPattern(getStatusEndpoint()), Json.encode(status)); - mockPostHoldings(); - Async async = context.async(); - interceptor = interceptAndStop(HOLDINGS_SERVICE_ADDRESS, SNAPSHOT_CREATED_ACTION, - message -> async.complete()); - vertx.eventBus().addOutboundInterceptor(interceptor); - - loadServiceFacade.createSnapshot(new ConfigurationMessage(stubConfiguration, STUB_CREDENTIALS_ID, STUB_TENANT)); - - async.await(TIMEOUT); - - WireMock.verify(0, - postRequestedFor(new UrlPathPattern(new EqualToPattern(RMAPI_POST_TRANSACTIONS_HOLDINGS_URL), false))); - } - - private void mockPostHoldings() { - stubFor(post(new UrlPathPattern(new EqualToPattern(RMAPI_POST_TRANSACTIONS_HOLDINGS_URL), false)) - .willReturn(new ResponseDefinitionBuilder() - .withBody(Json.encode(createTransactionId())) - .withStatus(202))); - } - - private void mockEmptyTransactionList() { - HoldingsTransactionIdsList emptyTransactionList = - HoldingsTransactionIdsList.builder().holdingsDownloadTransactionIds(Collections.emptyList()).build(); - mockGetWithBody(new EqualToPattern(RMAPI_TRANSACTIONS_URL), Json.encode(emptyTransactionList)); - } - - private String getStatusEndpoint() { - return String.format(RMAPI_TRANSACTION_STATUS_URL, TransactionLoadServiceFacadeTest.TRANSACTION_ID); - } - - private TransactionId createTransactionId() { - return TransactionId.builder().transactionId(TransactionLoadServiceFacadeTest.TRANSACTION_ID).build(); - } - - private void setupDefaultLoadKbConfiguration() { - saveKbCredentials(STUB_CREDENTIALS_ID, getWiremockUrl(), vertx); - saveStatusNotStarted(STUB_CREDENTIALS_ID, vertx); - insertRetryStatus(STUB_CREDENTIALS_ID, vertx); - } - - private void tearDownHoldingsData() { - clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); - } -} diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/package-info.java b/src/test/java/org/folio/rest/impl/integrationsuite/package-info.java deleted file mode 100644 index 6d362eed9..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * This package contains tests that are run as part of IntegrationTestSuite. - * By default test classes in this package are ignored during build. - * To make sure that tests run during build add them to org.folio.rest.impl.IntegrationTestSuite. - */ - -package org.folio.rest.impl.integrationsuite; diff --git a/src/test/java/org/folio/rest/util/IdParserTest.java b/src/test/java/org/folio/rest/util/IdParserTest.java index 52a4cdd1f..3f9d4a15c 100644 --- a/src/test/java/org/folio/rest/util/IdParserTest.java +++ b/src/test/java/org/folio/rest/util/IdParserTest.java @@ -1,33 +1,36 @@ package org.folio.rest.util; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import jakarta.validation.ValidationException; import org.folio.holdingsiq.model.ResourceId; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class IdParserTest { +class IdParserTest { @Test - public void parseResourceIdWhenIdIsValid() { + void parseResourceIdWhenIdIsValid() { ResourceId resourceId = IdParser.parseResourceId("1-2-3"); - assertEquals(1, resourceId.getProviderIdPart()); - assertEquals(2, resourceId.getPackageIdPart()); - assertEquals(3, resourceId.getTitleIdPart()); + assertEquals(1, resourceId.providerIdPart()); + assertEquals(2, resourceId.packageIdPart()); + assertEquals(3, resourceId.titleIdPart()); } - @Test(expected = ValidationException.class) - public void parseResourceIdThrowsExceptionWhenIdIsInvalid() { - IdParser.parseResourceId("a-b-c"); + @Test + void parseResourceIdThrowsExceptionWhenIdIsInvalid() { + assertThrows(ValidationException.class, () -> + IdParser.parseResourceId("a-b-c")); } - @Test(expected = ValidationException.class) - public void parseResourceIdThrowsExceptionWhenIdIsMissing() { - IdParser.parseResourceId(""); + @Test + void parseResourceIdThrowsExceptionWhenIdIsMissing() { + assertThrows(ValidationException.class, () -> + IdParser.parseResourceId("")); } @Test - public void parseTitleIdWhenIdIsValid() { + void parseTitleIdWhenIdIsValid() { long titleId = IdParser.parseTitleId("123"); assertEquals(123, titleId); } diff --git a/src/test/java/org/folio/rest/validator/AccessTypesBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/AccessTypesBodyValidatorTest.java index 095384962..f33240ffd 100644 --- a/src/test/java/org/folio/rest/validator/AccessTypesBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/AccessTypesBodyValidatorTest.java @@ -1,26 +1,26 @@ package org.folio.rest.validator; import static org.apache.commons.lang3.RandomStringUtils.insecure; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.folio.rest.exception.InputValidationException; import org.folio.rest.jaxrs.model.AccessType; import org.folio.rest.jaxrs.model.AccessTypeDataAttributes; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class AccessTypesBodyValidatorTest { +class AccessTypesBodyValidatorTest { private final AccessTypesBodyValidator validator = new AccessTypesBodyValidator(75, 150); @Test - public void shouldThrowExceptionWhenNoPutBody() { + void shouldThrowExceptionWhenNoPutBody() { var exception = assertThrows(InputValidationException.class, () -> validator.validate(null, null)); assertEquals("Invalid request body", exception.getMessage()); } @Test - public void shouldThrowExceptionWhenEmptyPostDataAttributes() { + void shouldThrowExceptionWhenEmptyPostDataAttributes() { final AccessType request = stubAccessType(); request.setAttributes(new AccessTypeDataAttributes()); var exception = assertThrows(InputValidationException.class, () -> validator.validate(null, request)); @@ -28,7 +28,7 @@ public void shouldThrowExceptionWhenEmptyPostDataAttributes() { } @Test - public void shouldThrowExceptionWhenNameIsTooLong() { + void shouldThrowExceptionWhenNameIsTooLong() { final AccessType request = stubAccessType(); request.getAttributes().setName(insecure().nextAlphanumeric(76)); var exception = assertThrows(InputValidationException.class, () -> validator.validate(null, request)); @@ -36,7 +36,7 @@ public void shouldThrowExceptionWhenNameIsTooLong() { } @Test - public void shouldThrowExceptionWhenDescriptionIsTooLong() { + void shouldThrowExceptionWhenDescriptionIsTooLong() { final AccessType request = stubAccessType(); request.getAttributes().setDescription(insecure().nextAlphanumeric(151)); var exception = assertThrows(InputValidationException.class, () -> validator.validate(null, request)); @@ -44,7 +44,7 @@ public void shouldThrowExceptionWhenDescriptionIsTooLong() { } @Test - public void shouldThrowExceptionWhenCredentialsIdNotEquals() { + void shouldThrowExceptionWhenCredentialsIdNotEquals() { final AccessType request = stubAccessType(); request.getAttributes().setCredentialsId("10"); var exception = assertThrows(InputValidationException.class, () -> validator.validate("1", request)); @@ -52,14 +52,14 @@ public void shouldThrowExceptionWhenCredentialsIdNotEquals() { } @Test - public void shouldNotThrowExceptionWhenDescriptionIsNull() { + void shouldNotThrowExceptionWhenDescriptionIsNull() { final AccessType request = stubAccessType(); request.getAttributes().setDescription(null); validator.validate(null, request); } @Test - public void shouldNotThrowExceptionWhenValidParameters() { + void shouldNotThrowExceptionWhenValidParameters() { final AccessType request = stubAccessType(); validator.validate(null, request); } diff --git a/src/test/java/org/folio/rest/validator/AssignedUsersBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/AssignedUsersBodyValidatorTest.java index 5296287aa..d57fd7cc7 100644 --- a/src/test/java/org/folio/rest/validator/AssignedUsersBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/AssignedUsersBodyValidatorTest.java @@ -1,15 +1,16 @@ package org.folio.rest.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; + import org.folio.rest.exception.InputValidationException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class AssignedUsersBodyValidatorTest { +class AssignedUsersBodyValidatorTest { private final AssignedUsersBodyValidator validator = new AssignedUsersBodyValidator(); @Test - public void shouldThrowExceptionWhenNoData() { - Assert.assertThrows(InputValidationException.class, () -> validator.validate(null)); + void shouldThrowExceptionWhenNoData() { + assertThrows(InputValidationException.class, () -> validator.validate(null)); } } diff --git a/src/test/java/org/folio/rest/validator/CustomLabelsPutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/CustomLabelsPutBodyValidatorTest.java index 07e07cf0a..3ca02ff1c 100644 --- a/src/test/java/org/folio/rest/validator/CustomLabelsPutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/CustomLabelsPutBodyValidatorTest.java @@ -1,8 +1,8 @@ package org.folio.rest.validator; import static org.apache.commons.lang3.RandomStringUtils.insecure; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Arrays; import java.util.Collections; @@ -11,30 +11,30 @@ import org.folio.rest.jaxrs.model.CustomLabel; import org.folio.rest.jaxrs.model.CustomLabelDataAttributes; import org.folio.rest.jaxrs.model.CustomLabelsPutRequest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class CustomLabelsPutBodyValidatorTest { +class CustomLabelsPutBodyValidatorTest { private final CustomLabelsPutBodyValidator validator = new CustomLabelsPutBodyValidator(new CustomLabelsProperties(50, 100)); @Test - public void shouldThrowExceptionWhenIdTooSmall() { + void shouldThrowExceptionWhenIdTooSmall() { assertInvalidCustomLabelId(0); } @Test - public void shouldThrowExceptionWhenIdTooBig() { + void shouldThrowExceptionWhenIdTooBig() { assertInvalidCustomLabelId(6); } @Test - public void shouldThrowExceptionWhenIdIsNull() { + void shouldThrowExceptionWhenIdIsNull() { assertInvalidCustomLabelId(null); } @Test - public void shouldThrowExceptionWhenNameIsTooLong() { + void shouldThrowExceptionWhenNameIsTooLong() { final CustomLabelsPutRequest request = new CustomLabelsPutRequest() .withData(Collections.singletonList( new CustomLabel().withAttributes( @@ -45,7 +45,7 @@ public void shouldThrowExceptionWhenNameIsTooLong() { } @Test - public void shouldThrowExceptionWhenPublicationFinderIsNull() { + void shouldThrowExceptionWhenPublicationFinderIsNull() { final CustomLabelsPutRequest request = new CustomLabelsPutRequest() .withData(Collections.singletonList(new CustomLabel().withAttributes( new CustomLabelDataAttributes() @@ -58,7 +58,7 @@ public void shouldThrowExceptionWhenPublicationFinderIsNull() { } @Test - public void shouldThrowExceptionWhenFullTextFinderIsNull() { + void shouldThrowExceptionWhenFullTextFinderIsNull() { final CustomLabelsPutRequest request = new CustomLabelsPutRequest() .withData(Collections.singletonList(new CustomLabel().withAttributes( new CustomLabelDataAttributes() @@ -71,7 +71,7 @@ public void shouldThrowExceptionWhenFullTextFinderIsNull() { } @Test - public void shouldThrowExceptionWhenIdsDuplicating() { + void shouldThrowExceptionWhenIdsDuplicating() { final CustomLabelsPutRequest request = new CustomLabelsPutRequest() .withData(Arrays.asList( new CustomLabel().withAttributes( @@ -91,7 +91,7 @@ public void shouldThrowExceptionWhenIdsDuplicating() { } @Test - public void shouldNotFallWhenPutBodyRequestIsValid() { + void shouldNotFallWhenPutBodyRequestIsValid() { final CustomLabelsPutRequest request = new CustomLabelsPutRequest() .withData(Arrays.asList( new CustomLabel().withAttributes( diff --git a/src/test/java/org/folio/rest/validator/CustomPackagePutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/CustomPackagePutBodyValidatorTest.java index 822f701c5..6508e4ba0 100644 --- a/src/test/java/org/folio/rest/validator/CustomPackagePutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/CustomPackagePutBodyValidatorTest.java @@ -1,23 +1,22 @@ package org.folio.rest.validator; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.folio.rest.exception.InputValidationException; -import org.folio.rest.impl.PackagesTestData; import org.folio.rest.jaxrs.model.ContentType; import org.folio.rest.jaxrs.model.Coverage; import org.folio.rest.jaxrs.model.PackagePutDataAttributes; -import org.junit.Test; +import org.folio.util.PackagesTestUtil; +import org.junit.jupiter.api.Test; -public class CustomPackagePutBodyValidatorTest { +class CustomPackagePutBodyValidatorTest { private final CustomPackagePutBodyValidator validator = new CustomPackagePutBodyValidator(); @Test - public void shouldThrowExceptionOnInvalidCoverageDate() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionOnInvalidCoverageDate() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) .withContentType(ContentType.MIXED_CONTENT) @@ -25,25 +24,25 @@ public void shouldThrowExceptionOnInvalidCoverageDate() { .withCustomCoverage(new Coverage() .withBeginCoverage("abcd-10-ab"))); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("beginCoverage")); + assertTrue(exception.getMessage().contains("beginCoverage")); } @Test - public void shouldThrowExceptionOnEmptyName() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionOnEmptyName() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withContentType(ContentType.MIXED_CONTENT) .withName("")); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("name")); + assertTrue(exception.getMessage().contains("name")); } @Test - public void shouldThrowExceptionOnNullContentType() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionOnNullContentType() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withName("package name")); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("contentType")); + assertTrue(exception.getMessage().contains("contentType")); } } diff --git a/src/test/java/org/folio/rest/validator/PackagePostValidatorTest.java b/src/test/java/org/folio/rest/validator/PackagePostValidatorTest.java index 797bfec15..e12068983 100644 --- a/src/test/java/org/folio/rest/validator/PackagePostValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/PackagePostValidatorTest.java @@ -1,82 +1,91 @@ package org.folio.rest.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; + import org.folio.rest.exception.InputValidationException; import org.folio.rest.jaxrs.model.ContentType; import org.folio.rest.jaxrs.model.Coverage; import org.folio.rest.jaxrs.model.PackagePostData; import org.folio.rest.jaxrs.model.PackagePostDataAttributes; import org.folio.rest.jaxrs.model.PackagePostRequest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class PackagePostValidatorTest { +class PackagePostValidatorTest { private final PackagesPostBodyValidator validator = new PackagesPostBodyValidator(); - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenNoPostBody() { + @Test + void shouldThrowExceptionWhenNoPostBody() { PackagePostRequest postRequest = null; - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenEmptyBody() { + @Test + void shouldThrowExceptionWhenEmptyBody() { PackagePostRequest postRequest = new PackagePostRequest(); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenNoPostData() { + @Test + void shouldThrowExceptionWhenNoPostData() { PackagePostRequest postRequest = new PackagePostRequest() .withData(null); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenEmptyPostData() { + @Test + void shouldThrowExceptionWhenEmptyPostData() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData()); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenEmptyPostDataAttributes() { + @Test + void shouldThrowExceptionWhenEmptyPostDataAttributes() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes())); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPostDataAttributesNameIsEmpty() { + @Test + void shouldThrowExceptionWhenPostDataAttributesNameIsEmpty() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName(""))); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPostDataAttributesTypeIsNull() { + @Test + void shouldThrowExceptionWhenPostDataAttributesTypeIsNull() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name"))); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsNull() { + @Test + void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsNull() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name").withContentType(ContentType.STREAMING_MEDIA) .withCustomCoverage(new Coverage()))); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - - public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyBeginDate() { + @Test + void shouldThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyBeginDate() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") @@ -85,11 +94,12 @@ public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyBegi .withBeginCoverage("") .withEndCoverage("2003-11-01")) )); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsInvalidFormat() { + @Test + void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsInvalidFormat() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() @@ -97,11 +107,12 @@ public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsIn .withContentType(ContentType.STREAMING_MEDIA) .withCustomCoverage(new Coverage() .withBeginCoverage("-01")))); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageEndDateIsInvalidFormat() { + @Test + void shouldThrowExceptionWhenPostDataAttributeCustomCoverageEndDateIsInvalidFormat() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() @@ -110,11 +121,12 @@ public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageEndDateIsInva .withCustomCoverage(new Coverage() .withBeginCoverage("2003-11-01") .withEndCoverage("-01")))); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsBeforeEndDate() { + @Test + void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsBeforeEndDate() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") @@ -123,11 +135,12 @@ public void shouldThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsBe .withBeginCoverage("2003-12-01") .withEndCoverage("2003-11-01")) )); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } @Test - public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageIsNull() { + void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageIsNull() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") @@ -137,7 +150,7 @@ public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageIsNull() { } @Test - public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidDates() { + void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidDates() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") @@ -150,7 +163,7 @@ public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidD } @Test - public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyDates() { + void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyDates() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") @@ -163,7 +176,7 @@ public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithEmptyD } @Test - public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsEmpty() { + void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateIsEmpty() { PackagePostRequest postRequest = new PackagePostRequest() .withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() @@ -175,7 +188,7 @@ public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageBeginDateI } @Test - public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsEmpty() { + void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsEmpty() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") @@ -188,7 +201,7 @@ public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidB } @Test - public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsNull() { + void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsNull() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") @@ -201,7 +214,7 @@ public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidB } @Test - public void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsNullw() { + void shouldNotThrowExceptionWhenPostDataAttributeCustomCoverageWithValidBeginDateAndEndDateIsNullw() { PackagePostRequest postRequest = new PackagePostRequest().withData(new PackagePostData() .withAttributes(new PackagePostDataAttributes() .withName("name") diff --git a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java index 886ef36c9..9ca1eae0c 100644 --- a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java @@ -1,109 +1,110 @@ package org.folio.rest.validator; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.List; import org.apache.commons.lang3.StringUtils; import org.folio.rest.exception.InputValidationException; -import org.folio.rest.impl.PackagesTestData; import org.folio.rest.jaxrs.model.Coverage; import org.folio.rest.jaxrs.model.PackagePutDataAttributes; +import org.folio.rest.jaxrs.model.PackageVisibility; import org.folio.rest.jaxrs.model.Token; -import org.folio.rest.jaxrs.model.VisibilityData; -import org.junit.Test; +import org.folio.util.PackagesTestUtil; +import org.junit.jupiter.api.Test; -public class PackagePutBodyValidatorTest { +class PackagePutBodyValidatorTest { private final PackagePutBodyValidator validator = new PackagePutBodyValidator(); @Test - public void shouldValidateWhenPackageIsSelected() { - validator.validate(PackagesTestData.getPackagePutRequest( + void shouldValidateWhenPackageIsSelected() { + var packagePutRequest = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) .withCustomCoverage(new Coverage()) .withAllowKbToAddTitles(true) - .withVisibilityData(new VisibilityData() - .withIsHidden(false) - .withReason("")))); + ); + assertDoesNotThrow(() -> validator.validate(packagePutRequest)); } @Test - public void shouldThrowExceptionWhenPackageIsNotSelectedAndIsHiddenIsTrue() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionWhenPackageIsNotSelectedAndIsHiddenIsTrue() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(false) - .withVisibilityData(new VisibilityData() - .withIsHidden(true))); + .withVisibility(List.of(new PackageVisibility().withCategory(PackageVisibility.Category.PF).withHidden(true))) + ); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("isHidden")); + assertTrue(exception.getMessage().contains("visibility")); } @Test - public void shouldThrowExceptionWhenPackageIsNotSelectedAndCoverageIsNotEmpty() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionWhenPackageIsNotSelectedAndCoverageIsNotEmpty() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(false) .withCustomCoverage(new Coverage() .withBeginCoverage("2000-01-01"))); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("beginCoverage")); + assertTrue(exception.getMessage().contains("beginCoverage")); } @Test - public void shouldThrowExceptionWhenPackageIsNotSelectedAndAllowToAddTitlesTrue() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionWhenPackageIsNotSelectedAndAllowToAddTitlesTrue() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(false) .withAllowKbToAddTitles(true)); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("allowKbToAddTitles")); + assertTrue(exception.getMessage().contains("allowKbToAddTitles")); } @Test - public void shouldThrowExceptionWhenPackageIsNotSelectedAndTokenIsNotEmpty() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionWhenPackageIsNotSelectedAndTokenIsNotEmpty() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(false) .withPackageToken(new Token().withValue("tokenValue"))); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("value")); + assertTrue(exception.getMessage().contains("value")); } @Test - public void shouldThrowExceptionWhenPackageIsSelectedAndTokenIsTooLong() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionWhenPackageIsSelectedAndTokenIsTooLong() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) .withPackageToken(new Token().withValue(StringUtils.repeat("tokenvalue", 200)))); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("value")); + assertTrue(exception.getMessage().contains("value")); } @Test - public void shouldThrowExceptionWhenPackageIsSelectedAndCoverageDateIsInvalid() { - var request = PackagesTestData.getPackagePutRequest( + void shouldThrowExceptionWhenPackageIsSelectedAndCoverageDateIsInvalid() { + var request = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) .withCustomCoverage(new Coverage() .withBeginCoverage("abcd-ab-ab"))); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("beginCoverage")); + assertTrue(exception.getMessage().contains("beginCoverage")); } @Test - public void shouldValidateWhenPackageIsSelectedAndCoverageDateIsEmpty() { - validator.validate(PackagesTestData.getPackagePutRequest( + void shouldValidateWhenPackageIsSelectedAndCoverageDateIsEmpty() { + var packagePutRequest = PackagesTestUtil.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(true) .withCustomCoverage(new Coverage() - .withBeginCoverage("")))); + .withBeginCoverage(""))); + assertDoesNotThrow(() -> validator.validate(packagePutRequest)); } } diff --git a/src/test/java/org/folio/rest/validator/PackageTagsPutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/PackageTagsPutBodyValidatorTest.java index 6996c888c..693351712 100644 --- a/src/test/java/org/folio/rest/validator/PackageTagsPutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/PackageTagsPutBodyValidatorTest.java @@ -1,33 +1,37 @@ package org.folio.rest.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; + import org.folio.rest.exception.InputValidationException; import org.folio.rest.jaxrs.model.ContentType; import org.folio.rest.jaxrs.model.PackageTagsDataAttributes; import org.folio.rest.jaxrs.model.PackageTagsPutData; import org.folio.rest.jaxrs.model.PackageTagsPutRequest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class PackageTagsPutBodyValidatorTest { +class PackageTagsPutBodyValidatorTest { private final PackageTagsPutBodyValidator validator = new PackageTagsPutBodyValidator(); - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenNameIsEmpty() { + @Test + void shouldThrowExceptionWhenNameIsEmpty() { PackageTagsPutRequest request = new PackageTagsPutRequest() .withData(new PackageTagsPutData() .withAttributes(new PackageTagsDataAttributes() .withName("") .withContentType(ContentType.E_BOOK) )); - validator.validate(request); + assertThrows(InputValidationException.class, () -> + validator.validate(request)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenContentTypeIsNull() { + @Test + void shouldThrowExceptionWhenContentTypeIsNull() { PackageTagsPutRequest request = new PackageTagsPutRequest() .withData(new PackageTagsPutData() .withAttributes(new PackageTagsDataAttributes() .withName("name") )); - validator.validate(request); + assertThrows(InputValidationException.class, () -> + validator.validate(request)); } } diff --git a/src/test/java/org/folio/rest/validator/ProviderPutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/ProviderPutBodyValidatorTest.java index a98b1aa5b..97404d0a2 100644 --- a/src/test/java/org/folio/rest/validator/ProviderPutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/ProviderPutBodyValidatorTest.java @@ -1,25 +1,27 @@ package org.folio.rest.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; + import org.apache.commons.lang3.RandomStringUtils; import org.folio.rest.exception.InputValidationException; import org.folio.rest.jaxrs.model.ProviderPutData; import org.folio.rest.jaxrs.model.ProviderPutDataAttributes; import org.folio.rest.jaxrs.model.ProviderPutRequest; import org.folio.rest.jaxrs.model.Token; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class ProviderPutBodyValidatorTest { +class ProviderPutBodyValidatorTest { private final ProviderPutBodyValidator validator = new ProviderPutBodyValidator(); @Test - public void shouldNotThrowExceptionWhenTokenIsMissing() { + void shouldNotThrowExceptionWhenTokenIsMissing() { ProviderPutRequest request = new ProviderPutRequest(); validator.validate(request); } @Test - public void shouldNotThrowExceptionWhenTokenIsValidLength() { + void shouldNotThrowExceptionWhenTokenIsValidLength() { Token providerToken = new Token(); providerToken.setValue(RandomStringUtils.insecure().nextAlphanumeric(500)); @@ -28,13 +30,13 @@ public void shouldNotThrowExceptionWhenTokenIsValidLength() { validator.validate(request); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenTokenIsTooLong() { + @Test + void shouldThrowExceptionWhenTokenIsTooLong() { Token providerToken = new Token(); providerToken.setValue(RandomStringUtils.insecure().nextAlphanumeric(501)); - ProviderPutRequest request = new ProviderPutRequest() .withData(new ProviderPutData().withAttributes(new ProviderPutDataAttributes().withProviderToken(providerToken))); - validator.validate(request); + assertThrows(InputValidationException.class, () -> + validator.validate(request)); } } diff --git a/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java b/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java index bd062a58d..e829b6470 100644 --- a/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java @@ -1,17 +1,19 @@ package org.folio.rest.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; + import java.util.Collections; import java.util.List; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.Titles; import org.folio.rest.exception.InputValidationException; import org.folio.rest.jaxrs.model.ResourcePostData; import org.folio.rest.jaxrs.model.ResourcePostDataAttributes; import org.folio.rest.jaxrs.model.ResourcePostRequest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class ResourcePostValidatorTest { +class ResourcePostValidatorTest { private static final String PACKAGE_ID = "123-456"; private static final String TITLE_ID = "789"; @@ -21,59 +23,66 @@ public class ResourcePostValidatorTest { private final ResourcePostValidator validator = new ResourcePostValidator(); @Test - public void shouldValidateRequest() { + void shouldValidateRequest() { validator.validate(createRequest(PACKAGE_ID, TITLE_ID, "http://example.com")); } @Test - public void shouldValidateWhenUrlIsNullOrEmpty() { + void shouldValidateWhenUrlIsNullOrEmpty() { validator.validate(createRequest(PACKAGE_ID, TITLE_ID, null)); validator.validate(createRequest(PACKAGE_ID, TITLE_ID, "")); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenTitleIdIsNotPresent() { - validator.validate(createRequest(PACKAGE_ID, null, "http://example.com")); + @Test + void shouldThrowExceptionWhenTitleIdIsNotPresent() { + var request = createRequest(PACKAGE_ID, null, "http://example.com"); + assertThrows(InputValidationException.class, () -> validator.validate(request)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPackageIdIsNotPresent() { - validator.validate(createRequest(null, TITLE_ID, "http://example.com")); + @Test + void shouldThrowExceptionWhenPackageIdIsNotPresent() { + var request = createRequest(null, TITLE_ID, "http://example.com"); + assertThrows(InputValidationException.class, () -> validator.validate(request)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenUrlIsInvalid() { - validator.validate(createRequest(PACKAGE_ID, TITLE_ID, "hdttp://example.com")); + @Test + void shouldThrowExceptionWhenUrlIsInvalid() { + var request = createRequest(PACKAGE_ID, TITLE_ID, "hdttp://example.com"); + assertThrows(InputValidationException.class, () -> validator.validate(request)); } @Test - public void shouldValidateTitleAndPackage() { + void shouldValidateTitleAndPackage() { validator.validateRelatedObjects( createPackage().build(), createTitle().build(), createTitles().build()); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenPackageIsNotCustom() { - PackageByIdData packageData = createPackage() + @Test + void shouldThrowExceptionWhenPackageIsNotCustom() { + PackageData packageData = createPackage() .isCustom(false) .build(); - validator.validateRelatedObjects( - packageData, - createTitle().build(), - createTitles().build()); + Title build = createTitle().build(); + Titles build1 = createTitles().build(); + assertThrows(InputValidationException.class, () -> + validator.validateRelatedObjects( + packageData, + build, + build1)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenTitleIsAlreadyAddedToPackage() { + @Test + void shouldThrowExceptionWhenTitleIsAlreadyAddedToPackage() { Title title = createTitle().build(); Titles titles = createTitles().titleList(Collections.singletonList(title)).build(); - PackageByIdData packageData = createPackage().build(); - validator.validateRelatedObjects( - packageData, - title, - titles); + PackageData packageData = createPackage().build(); + assertThrows(InputValidationException.class, () -> + validator.validateRelatedObjects( + packageData, + title, + titles)); } private Titles.TitlesBuilder createTitles() { @@ -92,8 +101,8 @@ private ResourcePostRequest createRequest(String packageId, String titleId, Stri return request; } - private PackageByIdData.PackageByIdDataBuilder createPackage() { - return PackageByIdData.byIdBuilder() + private PackageData.PackageDataBuilder createPackage() { + return PackageData.builder() .packageName("package") .vendorId(123) .packageId(456) diff --git a/src/test/java/org/folio/rest/validator/ResourcePutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/ResourcePutBodyValidatorTest.java index d7af1b23a..439a8752c 100644 --- a/src/test/java/org/folio/rest/validator/ResourcePutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/ResourcePutBodyValidatorTest.java @@ -1,33 +1,33 @@ package org.folio.rest.validator; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.apache.commons.lang3.RandomStringUtils; import org.folio.properties.customlabels.CustomLabelsProperties; import org.folio.rest.exception.InputValidationException; -import org.folio.rest.impl.ResourcesTestData; import org.folio.rest.jaxrs.model.EmbargoPeriod; import org.folio.rest.jaxrs.model.EmbargoPeriod.EmbargoUnit; import org.folio.rest.jaxrs.model.ResourcePutDataAttributes; import org.folio.rest.jaxrs.model.VisibilityData; -import org.junit.Test; +import org.folio.util.ResourcesTestUtil; +import org.junit.jupiter.api.Test; -public class ResourcePutBodyValidatorTest { +class ResourcePutBodyValidatorTest { private final ResourcePutBodyValidator validator = new ResourcePutBodyValidator(new CustomLabelsProperties(50, 100)); @Test - public void shouldNotThrowExceptionWhenUrlIsValidFormatForCustomResource() { - validator.validate(ResourcesTestData.getResourcePutRequest( + void shouldNotThrowExceptionWhenUrlIsValidFormatForCustomResource() { + validator.validate(ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(true) .withUrl("https://hello")), true); } @Test - public void shouldThrowExceptionWhenUrlIsInvalidFormatForCustomResource() { - var request = ResourcesTestData.getResourcePutRequest( + void shouldThrowExceptionWhenUrlIsInvalidFormatForCustomResource() { + var request = ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(true) .withUrl("hello")); @@ -36,8 +36,8 @@ public void shouldThrowExceptionWhenUrlIsInvalidFormatForCustomResource() { } @Test - public void shouldThrowExceptionWhenCvgStmtExceedsLengthForCustomResource() { - var request = ResourcesTestData.getResourcePutRequest( + void shouldThrowExceptionWhenCvgStmtExceedsLengthForCustomResource() { + var request = ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(true) .withCoverageStatement(RandomStringUtils.insecure().nextAlphanumeric(251))); @@ -46,16 +46,16 @@ public void shouldThrowExceptionWhenCvgStmtExceedsLengthForCustomResource() { } @Test - public void shouldNotThrowExceptionWhenCvgStmtIsValidForCustomResource() { - validator.validate(ResourcesTestData.getResourcePutRequest( + void shouldNotThrowExceptionWhenCvgStmtIsValidForCustomResource() { + validator.validate(ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(true) .withCoverageStatement("my test coverage statement")), true); } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndIsHiddenIsTrue() { - var request = ResourcesTestData.getResourcePutRequest( + void shouldThrowExceptionWhenResourceIsNotSelectedAndIsHiddenIsTrue() { + var request = ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(false) .withVisibilityData(new VisibilityData().withIsHidden(true))); @@ -64,8 +64,8 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndIsHiddenIsTrue() { } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndCvgStmtIsNotNull() { - var request = ResourcesTestData.getResourcePutRequest( + void shouldThrowExceptionWhenResourceIsNotSelectedAndCvgStmtIsNotNull() { + var request = ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(false) .withCoverageStatement("hello")); @@ -74,8 +74,8 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndCvgStmtIsNotNull() { } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedFieldIsNotNull() { - var request = ResourcesTestData.getResourcePutRequest( + void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedFieldIsNotNull() { + var request = ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(false) .withUserDefinedField1("not null")); @@ -84,7 +84,7 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedFieldIsNo } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField2IsNotNull() { + void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField2IsNotNull() { testUserDefinedFieldValidation( new ResourcePutDataAttributes() .withIsSelected(false) @@ -92,7 +92,7 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField2IsN } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField3IsNotNull() { + void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField3IsNotNull() { testUserDefinedFieldValidation( new ResourcePutDataAttributes() .withIsSelected(false) @@ -100,7 +100,7 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField3IsN } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField4IsNotNull() { + void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField4IsNotNull() { testUserDefinedFieldValidation( new ResourcePutDataAttributes() .withIsSelected(false) @@ -108,7 +108,7 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField4IsN } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField5IsNotNull() { + void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField5IsNotNull() { testUserDefinedFieldValidation( new ResourcePutDataAttributes() .withIsSelected(false) @@ -116,8 +116,8 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndUserDefinedField5IsN } @Test - public void shouldThrowExceptionWhenUserDefinedFieldIsLongerThanAllowed() { - var request = ResourcesTestData.getResourcePutRequest( + void shouldThrowExceptionWhenUserDefinedFieldIsLongerThanAllowed() { + var request = ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(true) .withUserDefinedField1(RandomStringUtils.insecure().nextAlphanumeric(101))); @@ -127,8 +127,8 @@ public void shouldThrowExceptionWhenUserDefinedFieldIsLongerThanAllowed() { } @Test - public void shouldThrowExceptionWhenResourceIsNotSelectedAndCustomEmbargoIsNotNull() { - var request = ResourcesTestData.getResourcePutRequest( + void shouldThrowExceptionWhenResourceIsNotSelectedAndCustomEmbargoIsNotNull() { + var request = ResourcesTestUtil.getResourcePutRequest( new ResourcePutDataAttributes() .withIsSelected(false) .withCustomEmbargoPeriod(new EmbargoPeriod().withEmbargoUnit(EmbargoUnit.DAYS))); @@ -138,7 +138,7 @@ public void shouldThrowExceptionWhenResourceIsNotSelectedAndCustomEmbargoIsNotNu } private void testUserDefinedFieldValidation(ResourcePutDataAttributes value) { - var request = ResourcesTestData.getResourcePutRequest(value); + var request = ResourcesTestUtil.getResourcePutRequest(value); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request, false)); assertEquals("Resource cannot be updated unless added to holdings", exception.getMessage()); diff --git a/src/test/java/org/folio/rest/validator/TitlePostBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/TitlePostBodyValidatorTest.java index 9a31bdad3..dd6c9f88a 100644 --- a/src/test/java/org/folio/rest/validator/TitlePostBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/TitlePostBodyValidatorTest.java @@ -1,5 +1,7 @@ package org.folio.rest.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; + import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; @@ -12,166 +14,177 @@ import org.folio.rest.jaxrs.model.TitlePostIncluded; import org.folio.rest.jaxrs.model.TitlePostIncludedPackageId; import org.folio.rest.jaxrs.model.TitlePostRequest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class TitlePostBodyValidatorTest { +class TitlePostBodyValidatorTest { private static final String TEXT_LONGER_THAN_250_CHARACTERS = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Ae" - + "nean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridicul" - + "us mus. Donec quam felis, ultricies nec, pellentesque eu, pretium q"; + + "nean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridicul" + + "us mus. Donec quam felis, ultricies nec, pellentesque eu, pretium q"; private static final String TEXT_LONGER_THAN_400_CHARACTERS = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Ae" - + "nean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridicul" - + "us mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequ" - + "at massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In" - + " enim justo, rhoncus ut, imperdiet a,"; + + "nean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridicul" + + "us mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequ" + + "at massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In" + + " enim justo, rhoncus ut, imperdiet a,"; private static final String TEXT_LONGER_THAN_1500_CHARACTERS = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget d" - + "olor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, " - + "nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium " - + "quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliqu" - + "et nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vi" - + "ae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dap" - + "ibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo " - + "ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapi" - + "bus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius l" - + "aoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitu" - + "r ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus" - + " eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque s" - + "ed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecen" - + "as nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis fauci" - + "bus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo." - + " Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, " - + "leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero" - + ". Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis s" - + "ed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi"; + + "olor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, " + + "nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium " + + "quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliqu" + + "et nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vi" + + "ae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dap" + + "ibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo " + + "ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapi" + + "bus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius l" + + "aoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitu" + + "r ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus" + + " eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque s" + + "ed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecen" + + "as nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis fauci" + + "bus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo." + + " Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, " + + "leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero" + + ". Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis s" + + "ed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi"; private static final String TITLE_TEST_NAME = "Title Test Name"; private final TitlesPostBodyValidator validator = new TitlesPostBodyValidator( new TitleCommonRequestAttributesValidator(), new CustomLabelsProperties(50, 100) ); - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenNoPostBody() { + @Test + void shouldThrowExceptionWhenNoPostBody() { TitlePostRequest postRequest = null; - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenEmptyBody() { + @Test + void shouldThrowExceptionWhenEmptyBody() { TitlePostRequest postRequest = new TitlePostRequest(); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenNoPostData() { + @Test + void shouldThrowExceptionWhenNoPostData() { TitlePostRequest postRequest = new TitlePostRequest() .withData(null); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionWhenEmptyPostData() { + @Test + void shouldThrowExceptionWhenEmptyPostData() { TitlePostRequest postRequest = new TitlePostRequest() .withData(new TitlePostData()); - validator.validate(postRequest); + assertThrows(InputValidationException.class, () -> + validator.validate(postRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfTitleDescriptionIsTooLong() { + @Test + void shouldThrowExceptionIfTitleDescriptionIsTooLong() { TitlePostRequest titlePostRequest = new TitlePostRequest(); titlePostRequest .withData(new TitlePostData() .withAttributes(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withDescription(TEXT_LONGER_THAN_1500_CHARACTERS))); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfTitleNameIsTooLong() { + @Test + void shouldThrowExceptionIfTitleNameIsTooLong() { TitlePostRequest titlePostRequest = new TitlePostRequest(); titlePostRequest .withData(new TitlePostData() .withAttributes(new TitlePostDataAttributes() .withName(TEXT_LONGER_THAN_400_CHARACTERS))); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfTitleNameIsNull() { + @Test + void shouldThrowExceptionIfTitleNameIsNull() { TitlePostRequest titlePostRequest = new TitlePostRequest(); titlePostRequest .withData(new TitlePostData() .withAttributes(new TitlePostDataAttributes() .withName(null))); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfTitleNameIsEmpty() { + @Test + void shouldThrowExceptionIfTitleNameIsEmpty() { TitlePostRequest titlePostRequest = new TitlePostRequest(); titlePostRequest .withData(new TitlePostData() .withAttributes(new TitlePostDataAttributes() .withName(""))); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfTitlePublisherNameIsTooLong() { + @Test + void shouldThrowExceptionIfTitlePublisherNameIsTooLong() { TitlePostRequest titlePostRequest = new TitlePostRequest(); titlePostRequest .withData(new TitlePostData() .withAttributes(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublisherName(TEXT_LONGER_THAN_250_CHARACTERS))); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfTitleEditionIsTooLong() { + @Test + void shouldThrowExceptionIfTitleEditionIsTooLong() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublisherName( TEXT_LONGER_THAN_250_CHARACTERS)); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfTitleIdentifierIdTooLong() { + @Test + void shouldThrowExceptionIfTitleIdentifierIdTooLong() { TitlePostRequest titlePostRequest = new TitlePostRequest(); List<Identifier> titleIdentifiers = new ArrayList<>(); titleIdentifiers.add(new Identifier().withId("1234567-1234567-1234567")); - titlePostRequest .withData(new TitlePostData() .withAttributes(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublisherName("Test publisher name").withIdentifiers(titleIdentifiers))); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } - @Test(expected = InputValidationException.class) - public void shouldThrowExceptionIfUserDefinedFieldIsTooLong() { + @Test + void shouldThrowExceptionIfUserDefinedFieldIsTooLong() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withUserDefinedField1(StringUtils.repeat("*", 101)) .withPublicationType(PublicationType.BOOK)); + assertThrows(InputValidationException.class, () -> - validator.validate(titlePostRequest); + validator.validate(titlePostRequest)); } @Test - public void shouldNotThrowExceptionIfTitleDescriptionIsEmpty() { + void shouldNotThrowExceptionIfTitleDescriptionIsEmpty() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublicationType(PublicationType.BOOK) @@ -181,7 +194,7 @@ public void shouldNotThrowExceptionIfTitleDescriptionIsEmpty() { } @Test - public void shouldNotThrowExceptionIfTitleDescriptionIsNull() { + void shouldNotThrowExceptionIfTitleDescriptionIsNull() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublicationType(PublicationType.BOOK) @@ -191,7 +204,7 @@ public void shouldNotThrowExceptionIfTitleDescriptionIsNull() { } @Test - public void shouldNotThrowExceptionIfTitleEditionIsEmpty() { + void shouldNotThrowExceptionIfTitleEditionIsEmpty() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublicationType(PublicationType.BOOK) @@ -201,7 +214,7 @@ public void shouldNotThrowExceptionIfTitleEditionIsEmpty() { } @Test - public void shouldNotThrowExceptionIfTitleEditionIsNull() { + void shouldNotThrowExceptionIfTitleEditionIsNull() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublicationType(PublicationType.BOOK) @@ -211,7 +224,7 @@ public void shouldNotThrowExceptionIfTitleEditionIsNull() { } @Test - public void shouldNotThrowExceptionIfTitlePublisherNameIsNull() { + void shouldNotThrowExceptionIfTitlePublisherNameIsNull() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublicationType(PublicationType.BOOK) @@ -221,7 +234,7 @@ public void shouldNotThrowExceptionIfTitlePublisherNameIsNull() { } @Test - public void shouldNotThrowExceptionIfTitlePublisherNameIsEmpty() { + void shouldNotThrowExceptionIfTitlePublisherNameIsEmpty() { TitlePostRequest titlePostRequest = createRequest(new TitlePostDataAttributes() .withName(TITLE_TEST_NAME) .withPublicationType(PublicationType.BOOK) diff --git a/src/test/java/org/folio/rest/validator/kbcredentials/KbCredentialsBodyAttributesValidatorTest.java b/src/test/java/org/folio/rest/validator/kbcredentials/KbCredentialsBodyAttributesValidatorTest.java index 295687163..bc4c57788 100644 --- a/src/test/java/org/folio/rest/validator/kbcredentials/KbCredentialsBodyAttributesValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/kbcredentials/KbCredentialsBodyAttributesValidatorTest.java @@ -1,13 +1,13 @@ package org.folio.rest.validator.kbcredentials; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.folio.rest.exception.InputValidationException; import org.folio.rest.jaxrs.model.KbCredentialsDataAttributes; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class KbCredentialsBodyAttributesValidatorTest { +class KbCredentialsBodyAttributesValidatorTest { private static final int NAME_LENGTH_MAX = 10; @@ -15,7 +15,7 @@ public class KbCredentialsBodyAttributesValidatorTest { new KbCredentialsBodyAttributesValidator(NAME_LENGTH_MAX); @Test - public void shouldThrowExceptionWhenNullName() { + void shouldThrowExceptionWhenNullName() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withApiKey("key") .withCustomerId("custId") @@ -26,7 +26,7 @@ public void shouldThrowExceptionWhenNullName() { } @Test - public void shouldThrowExceptionWhenEmptyName() { + void shouldThrowExceptionWhenEmptyName() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("") .withApiKey("key") @@ -38,7 +38,7 @@ public void shouldThrowExceptionWhenEmptyName() { } @Test - public void shouldThrowExceptionWhenNameIsLongerThanMaxLength() { + void shouldThrowExceptionWhenNameIsLongerThanMaxLength() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("0".repeat(NAME_LENGTH_MAX + 1)) .withApiKey("key") @@ -50,7 +50,7 @@ public void shouldThrowExceptionWhenNameIsLongerThanMaxLength() { } @Test - public void shouldThrowExceptionWhenNullApiKey() { + void shouldThrowExceptionWhenNullApiKey() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("name") .withCustomerId("custId") @@ -61,7 +61,7 @@ public void shouldThrowExceptionWhenNullApiKey() { } @Test - public void shouldThrowExceptionWhenEmptyApiKey() { + void shouldThrowExceptionWhenEmptyApiKey() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("name") .withApiKey("") @@ -73,7 +73,7 @@ public void shouldThrowExceptionWhenEmptyApiKey() { } @Test - public void shouldThrowExceptionWhenNullCustomerId() { + void shouldThrowExceptionWhenNullCustomerId() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("name") .withApiKey("key") @@ -84,7 +84,7 @@ public void shouldThrowExceptionWhenNullCustomerId() { } @Test - public void shouldThrowExceptionWhenEmptyCustomerId() { + void shouldThrowExceptionWhenEmptyCustomerId() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("name") .withApiKey("key") @@ -96,7 +96,7 @@ public void shouldThrowExceptionWhenEmptyCustomerId() { } @Test - public void shouldThrowExceptionWhenNullUrl() { + void shouldThrowExceptionWhenNullUrl() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("name") .withApiKey("key") @@ -107,7 +107,7 @@ public void shouldThrowExceptionWhenNullUrl() { } @Test - public void shouldThrowExceptionWhenEmptyUrl() { + void shouldThrowExceptionWhenEmptyUrl() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("name") .withApiKey("key") @@ -119,7 +119,7 @@ public void shouldThrowExceptionWhenEmptyUrl() { } @Test - public void shouldThrowExceptionWhenInvalidUrl() { + void shouldThrowExceptionWhenInvalidUrl() { KbCredentialsDataAttributes attributes = new KbCredentialsDataAttributes() .withName("name") .withApiKey("key") diff --git a/src/test/java/org/folio/rmapi/PackageServiceImplTest.java b/src/test/java/org/folio/rmapi/PackageServiceImplTest.java index 2db2a3790..190a304e6 100644 --- a/src/test/java/org/folio/rmapi/PackageServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/PackageServiceImplTest.java @@ -1,61 +1,39 @@ package org.folio.rmapi; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGet; - -import com.github.tomakehurst.wiremock.common.Slf4jNotifier; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.junit.WireMockRule; -import com.github.tomakehurst.wiremock.matching.RegexPattern; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.readFile; + import com.github.tomakehurst.wiremock.matching.UrlPattern; import io.vertx.core.Vertx; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.Collections; import org.folio.cache.VertxCache; -import org.folio.holdingsiq.model.Configuration; import org.folio.holdingsiq.model.PackageId; -import org.junit.Rule; -import org.junit.Test; +import org.folio.util.WireMockTestBase; +import org.junit.jupiter.api.Test; -public class PackageServiceImplTest { +class PackageServiceImplTest extends WireMockTestBase { - protected static final String STUB_CUSTOMER_ID = "TEST_CUSTOMER_ID"; - private static final int STUB_PACKAGE_ID = 3964; - private static final int STUB_VENDOR_ID = 111111; + private static final int PACKAGE_ID = 3964; + private static final int VENDOR_ID = 111111; private static final String CUSTOM_PACKAGE_STUB_FILE = "responses/rmapi/packages/get-custom-package-by-id-response.json"; - @Rule - public WireMockRule userMockServer = new WireMockRule( - WireMockConfiguration.wireMockConfig() - .dynamicPort() - .notifier(new Slf4jNotifier(true))); - @Test - public void shouldReturnCachedPackage() throws IOException, URISyntaxException { - RegexPattern getPackagePattern = new RegexPattern( - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages/" + STUB_PACKAGE_ID); - - Configuration configuration = Configuration.builder() - .url("http://127.0.0.1:" + userMockServer.port()) - .customerId(STUB_CUSTOMER_ID) - .apiKey("API KEY") - .build(); - PackageServiceImpl service = new PackageServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, null, null, + void shouldReturnCachedPackage() { + var getPackagePattern = equalTo(packageRmApi(PACKAGE_ID)); + + var configuration = getStubConfiguration(); + var service = new PackageServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, null, null, new VertxCache<>(Vertx.vertx(), 60, "packageCache"), null); - mockGet(getPackagePattern, CUSTOM_PACKAGE_STUB_FILE); + mockGet(getPackagePattern, readFile(CUSTOM_PACKAGE_STUB_FILE)); - PackageId packageId = PackageId.builder() - .packageIdPart(STUB_PACKAGE_ID) - .providerIdPart(STUB_VENDOR_ID) - .build(); + var packageId = new PackageId(VENDOR_ID, PACKAGE_ID); service.retrievePackage(packageId, Collections.emptyList(), true).join(); service.retrievePackage(packageId, Collections.emptyList(), true).join(); - verify(1, getRequestedFor(new UrlPattern(getPackagePattern, true))); + wm.verify(1, getRequestedFor(new UrlPattern(getPackagePattern, false))); } } diff --git a/src/test/java/org/folio/rmapi/ProviderServiceImplTest.java b/src/test/java/org/folio/rmapi/ProviderServiceImplTest.java index 9919eebb2..1edb677db 100644 --- a/src/test/java/org/folio/rmapi/ProviderServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/ProviderServiceImplTest.java @@ -1,51 +1,33 @@ package org.folio.rmapi; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGet; - -import com.github.tomakehurst.wiremock.common.Slf4jNotifier; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.junit.WireMockRule; -import com.github.tomakehurst.wiremock.matching.RegexPattern; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.readFile; + import com.github.tomakehurst.wiremock.matching.UrlPattern; import io.vertx.core.Vertx; -import java.io.IOException; -import java.net.URISyntaxException; import org.folio.cache.VertxCache; -import org.folio.holdingsiq.model.Configuration; -import org.junit.Rule; -import org.junit.Test; +import org.folio.util.WireMockTestBase; +import org.junit.jupiter.api.Test; -public class ProviderServiceImplTest { - protected static final String STUB_CUSTOMER_ID = "TEST_CUSTOMER_ID"; - private static final int STUB_VENDOR_ID = 111111; - private static final String VENDOR_STUB_FILE = "responses/rmapi/vendors/get-vendor-by-id-response.json"; +class ProviderServiceImplTest extends WireMockTestBase { - @Rule - public WireMockRule userMockServer = new WireMockRule( - WireMockConfiguration.wireMockConfig() - .dynamicPort() - .notifier(new Slf4jNotifier(true))); + private static final int VENDOR_ID = 111111; + private static final String VENDOR_STUB_FILE = "responses/rmapi/vendors/get-vendor-by-id-response.json"; @Test - public void shouldReturnCachedProviderOnSecondRequest() throws IOException, URISyntaxException { - RegexPattern getVendorPattern = - new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID); - - Configuration configuration = Configuration.builder() - .url("http://127.0.0.1:" + userMockServer.port()) - .customerId(STUB_CUSTOMER_ID) - .apiKey("API KEY") - .build(); - ProvidersServiceImpl service = new ProvidersServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, null, + void shouldReturnCachedProviderOnSecondRequest() { + var getVendorPattern = equalTo(vendorsRmApi(VENDOR_ID)); + + var configuration = getStubConfiguration(); + var service = new ProvidersServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, null, new VertxCache<>(Vertx.vertx(), 60, "vendorCache")); - mockGet(getVendorPattern, VENDOR_STUB_FILE); - service.retrieveProvider(STUB_VENDOR_ID, null, true).join(); - service.retrieveProvider(STUB_VENDOR_ID, null, true).join(); + mockGet(getVendorPattern, readFile(VENDOR_STUB_FILE)); + service.retrieveProvider(VENDOR_ID, null, true).join(); + service.retrieveProvider(VENDOR_ID, null, true).join(); - verify(1, getRequestedFor(new UrlPattern(getVendorPattern, true))); + wm.verify(1, getRequestedFor(new UrlPattern(getVendorPattern, false))); } } diff --git a/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java b/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java index d952205b1..ded17705b 100644 --- a/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java @@ -1,63 +1,41 @@ package org.folio.rmapi; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGet; - -import com.github.tomakehurst.wiremock.common.Slf4jNotifier; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.junit.WireMockRule; -import com.github.tomakehurst.wiremock.matching.RegexPattern; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.readFile; + import com.github.tomakehurst.wiremock.matching.UrlPattern; import io.vertx.core.Vertx; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.Collections; import org.folio.cache.VertxCache; -import org.folio.holdingsiq.model.Configuration; import org.folio.holdingsiq.model.ResourceId; -import org.junit.Rule; -import org.junit.Test; - -public class ResourceServiceImplTest { - protected static final String STUB_CUSTOMER_ID = "TEST_CUSTOMER_ID"; - private static final int STUB_PACKAGE_ID = 3964; - private static final int STUB_VENDOR_ID = 111111; - private static final int STUB_TITLE_ID = 985846; +import org.folio.util.WireMockTestBase; +import org.junit.jupiter.api.Test; + +class ResourceServiceImplTest extends WireMockTestBase { + + private static final int PACKAGE_ID = 3964; + private static final int VENDOR_ID = 111111; + private static final int TITLE_ID = 985846; + private static final String CUSTOM_RESOURCE_STUB_FILE = "responses/rmapi/resources/get-resource-by-id-success-response.json"; - @Rule - public WireMockRule userMockServer = new WireMockRule( - WireMockConfiguration.wireMockConfig() - .dynamicPort() - .notifier(new Slf4jNotifier(true))); - @Test - public void shouldReturnCachedResource() throws IOException, URISyntaxException { - RegexPattern getResourcePattern = new RegexPattern( - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages/" + STUB_PACKAGE_ID - + "/titles/" + STUB_TITLE_ID); - - Configuration configuration = Configuration.builder() - .url("http://127.0.0.1:" + userMockServer.port()) - .customerId(STUB_CUSTOMER_ID) - .apiKey("API KEY") - .build(); - ResourcesServiceImpl service = new ResourcesServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, null, null, + void shouldReturnCachedResource() { + var getResourcePattern = equalTo(resourcesRmApi(VENDOR_ID, PACKAGE_ID, TITLE_ID)); + + var configuration = getStubConfiguration(); + var service = new ResourcesServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, null, null, new VertxCache<>(Vertx.vertx(), 60, "resourceCache")); - mockGet(getResourcePattern, CUSTOM_RESOURCE_STUB_FILE); + mockGet(getResourcePattern, readFile(CUSTOM_RESOURCE_STUB_FILE)); - ResourceId resourceId = ResourceId.builder() - .packageIdPart(STUB_PACKAGE_ID) - .providerIdPart(STUB_VENDOR_ID) - .titleIdPart(STUB_TITLE_ID) - .build(); + var resourceId = new ResourceId(VENDOR_ID, PACKAGE_ID, TITLE_ID); service.retrieveResource(resourceId, Collections.emptyList(), true).join(); service.retrieveResource(resourceId, Collections.emptyList(), true).join(); - verify(1, getRequestedFor(new UrlPattern(getResourcePattern, true))); + wm.verify(1, getRequestedFor(new UrlPattern(getResourcePattern, true))); } } diff --git a/src/test/java/org/folio/rmapi/TitleServiceImplTest.java b/src/test/java/org/folio/rmapi/TitleServiceImplTest.java index 6e4e20ea1..06c328e1d 100644 --- a/src/test/java/org/folio/rmapi/TitleServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/TitleServiceImplTest.java @@ -1,22 +1,16 @@ package org.folio.rmapi; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; -import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGet; -import static org.junit.Assert.assertEquals; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.readFile; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import com.github.tomakehurst.wiremock.common.Slf4jNotifier; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.junit.WireMockRule; -import com.github.tomakehurst.wiremock.matching.RegexPattern; import com.github.tomakehurst.wiremock.matching.UrlPattern; import io.vertx.core.Vertx; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import org.folio.cache.VertxCache; @@ -24,69 +18,53 @@ import org.folio.holdingsiq.model.CustomerResources; import org.folio.holdingsiq.model.Title; import org.folio.rmapi.cache.TitleCacheKey; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.folio.util.WireMockTestBase; +import org.junit.jupiter.api.Test; -public class TitleServiceImplTest { +class TitleServiceImplTest extends WireMockTestBase { protected static final String STUB_CUSTOMER_ID = "TEST_CUSTOMER_ID"; - private static final int STUB_TITLE_ID = 123456; + private static final int TITLE_ID = 123456; private static final String TITLE_STUB_FILE = "responses/rmapi/titles/get-title-by-id-response.json"; - @Rule - public WireMockRule userMockServer = new WireMockRule( - WireMockConfiguration.wireMockConfig() - .dynamicPort() - .notifier(new Slf4jNotifier(true))); - - private Configuration configuration; - - @Before - public void setUp() { - configuration = Configuration.builder() - .url("http://127.0.0.1:" + userMockServer.port()) - .customerId(STUB_CUSTOMER_ID) - .apiKey("API KEY") - .build(); - } + private final Configuration configuration = getStubConfiguration(); @Test - public void shouldReturnCachedTitleOnSecondRequest() throws IOException, URISyntaxException { - RegexPattern getTitlePattern = new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_TITLE_ID); + void shouldReturnCachedTitleOnSecondRequest() { + var getTitlePattern = equalTo(titlesRmApi(TITLE_ID)); - TitlesServiceImpl service = new TitlesServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, + var service = new TitlesServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, new VertxCache<>(Vertx.vertx(), 60, "titleCache")); - mockGet(getTitlePattern, TITLE_STUB_FILE); - service.retrieveTitle(STUB_TITLE_ID, true).join(); - service.retrieveTitle(STUB_TITLE_ID, true).join(); + mockGet(getTitlePattern, readFile(TITLE_STUB_FILE)); + service.retrieveTitle(TITLE_ID, true).join(); + service.retrieveTitle(TITLE_ID, true).join(); - verify(1, getRequestedFor(new UrlPattern(getTitlePattern, true))); + wm.verify(1, getRequestedFor(new UrlPattern(getTitlePattern, true))); } @Test - public void shouldNotUseCache() throws IOException, URISyntaxException { - RegexPattern getTitlePattern = new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/titles/" + STUB_TITLE_ID); + void shouldNotUseCache() { + var getTitlePattern = equalTo(titlesRmApi(TITLE_ID)); - TitlesServiceImpl service = new TitlesServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, + var service = new TitlesServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, new VertxCache<>(Vertx.vertx(), 60, "titleCache")); - mockGet(getTitlePattern, TITLE_STUB_FILE); - service.retrieveTitle(STUB_TITLE_ID, false).join(); + mockGet(getTitlePattern, readFile(TITLE_STUB_FILE)); + service.retrieveTitle(TITLE_ID, false).join(); - verify(1, getRequestedFor(new UrlPattern(getTitlePattern, true))); + wm.verify(1, getRequestedFor(new UrlPattern(getTitlePattern, true))); } @Test - public void shouldUpdateCachedTitle() { + void shouldUpdateCachedTitle() { VertxCache<TitleCacheKey, Title> titleCache = mock(); var service = new TitlesServiceImpl(configuration, Vertx.vertx(), STUB_TENANT, titleCache); when(titleCache.getValue(any(TitleCacheKey.class))).thenReturn(buildTitleWithCustomerResource(1)); - Title title = buildTitleWithCustomerResource(2); + var title = buildTitleWithCustomerResource(2); service.updateCache(title); assertEquals(2, title.getCustomerResourcesList().size()); @@ -98,7 +76,7 @@ private Title buildTitleWithCustomerResource(int packageId) { .build(); return Title.builder() - .titleId(STUB_TITLE_ID) + .titleId(TITLE_ID) .customerResourcesList(new ArrayList<>(List.of(customerResource))) .build(); } diff --git a/src/test/java/org/folio/service/assignedusers/AssignedUsersServiceImplTest.java b/src/test/java/org/folio/service/assignedusers/AssignedUsersServiceImplTest.java index 76cc3facc..52bfaaa5a 100644 --- a/src/test/java/org/folio/service/assignedusers/AssignedUsersServiceImplTest.java +++ b/src/test/java/org/folio/service/assignedusers/AssignedUsersServiceImplTest.java @@ -3,6 +3,7 @@ import static java.util.concurrent.CompletableFuture.completedFuture; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.folio.util.TestUtil.result; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @@ -16,7 +17,7 @@ import javax.ws.rs.NotFoundException; import lombok.SneakyThrows; import org.apache.commons.collections4.map.CaseInsensitiveMap; -import org.folio.common.OkapiParams; +import org.folio.holdingsiq.model.RequestContext; import org.folio.okapi.common.XOkapiHeaders; import org.folio.repository.assigneduser.AssignedUserRepository; import org.folio.repository.assigneduser.DbAssignedUser; @@ -26,15 +27,18 @@ import org.folio.service.users.Group; import org.folio.service.users.User; import org.folio.service.users.UsersLookUpService; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) -public class AssignedUsersServiceImplTest { +@MockitoSettings(strictness = Strictness.WARN) +@ExtendWith(MockitoExtension.class) +class AssignedUsersServiceImplTest { private static final String TENANT_ID = "test"; private static final Map<String, String> HEADERS = new CaseInsensitiveMap<>(Map.of( @@ -53,7 +57,7 @@ public class AssignedUsersServiceImplTest { private UsersLookUpService usersLookUpService; @Test - public void testFindByCredentialsId_sortedByLastName() { + void findByCredentialsIdSortedByLastName() { var credId = UUID.randomUUID(); var user1Id = UUID.randomUUID(); var user2Id = UUID.randomUUID(); @@ -62,12 +66,12 @@ public void testFindByCredentialsId_sortedByLastName() { .thenReturn(completedFuture(List.of( DbAssignedUser.builder().credentialsId(credId).id(user1Id).build(), DbAssignedUser.builder().credentialsId(credId).id(user2Id).build()))); - when(usersLookUpService.lookUpUsers(eq(List.of(user1Id, user2Id)), any(OkapiParams.class))) + when(usersLookUpService.lookUpUsers(eq(List.of(user1Id, user2Id)), any(RequestContext.class))) .thenReturn(completedFuture(List.of(dummyUser(user1Id, groupId, "b"), dummyUser(user1Id, groupId, "a")))); - when(usersLookUpService.lookUpGroups(eq(List.of(groupId)), any(OkapiParams.class))) + when(usersLookUpService.lookUpGroups(eq(List.of(groupId)), any(RequestContext.class))) .thenReturn(completedFuture(List.of(Group.builder().id(groupId.toString()).group("group").build()))); - getResult(usersService.findByCredentialsId(credId.toString(), HEADERS)); + result(usersService.findByCredentialsId(credId.toString(), HEADERS)); var resultArgumentCaptor = ArgumentCaptor.forClass(UserCollectionDataConverter.UsersResult.class); verify(userCollectionConverter).convert(resultArgumentCaptor.capture()); @@ -81,7 +85,7 @@ public void testFindByCredentialsId_sortedByLastName() { @Test @SneakyThrows - public void shouldNotAssignNonExistentUser() { + void shouldNotAssignNonExistentUser() { var assignUserData = new AssignedUserId() .withId(UUID.randomUUID().toString()) .withCredentialsId(UUID.randomUUID().toString()); @@ -98,7 +102,7 @@ public void shouldNotAssignNonExistentUser() { @Test @SneakyThrows - public void shouldNotAssignUserIfLookupFails() { + void shouldNotAssignUserIfLookupFails() { var assignUserData = new AssignedUserId() .withId(UUID.randomUUID().toString()) .withCredentialsId(UUID.randomUUID().toString()); @@ -136,9 +140,4 @@ private User dummyUser(UUID user1Id, UUID groupId, String val) { .userName(val) .build(); } - - @SneakyThrows - private <T> void getResult(CompletableFuture<T> future) { - future.get(); - } } diff --git a/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java b/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java index 398d40055..297182fde 100644 --- a/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java +++ b/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java @@ -1,173 +1,104 @@ package org.folio.service.export; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.STUB_TOKEN; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TOKEN; +import static org.folio.util.TestUtil.result; +import static org.junit.jupiter.api.Assertions.assertEquals; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; import java.util.HashMap; import java.util.Map; -import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.RequestContext; import org.folio.okapi.common.XOkapiHeaders; -import org.folio.rest.impl.WireMockTestBase; import org.folio.service.locale.LocaleSettings; import org.folio.service.locale.LocaleSettingsService; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; +import org.folio.service.locale.LocaleSettingsServiceImpl; +import org.folio.util.WireMockTestBase; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class LocaleSettingsServiceImplTest extends WireMockTestBase { +class LocaleSettingsServiceImplTest extends WireMockTestBase { - @Autowired - private LocaleSettingsService localeSettingsService; + private final LocaleSettingsService localeSettingsService = new LocaleSettingsServiceImpl(); - private OkapiData okapiParams; + private RequestContext requestContext; - @Override - @Before - public void setUp() throws Exception { - super.setUp(); + @BeforeEach + void setUp() { Map<String, String> headers = new HashMap<>(); headers.put(XOkapiHeaders.TOKEN, STUB_TOKEN); headers.put(XOkapiHeaders.TENANT, STUB_TENANT); - headers.put(XOkapiHeaders.URL, getWiremockUrl()); - okapiParams = new OkapiData(headers); + headers.put(XOkapiHeaders.URL, wm.baseUrl()); + requestContext = new RequestContext(headers); } @Test - public void shouldReturnValidSettings(TestContext context) { - var async = context.async(); + void shouldReturnValidSettings() { mockSuccessfulLocaleResponse(); - var future = localeSettingsService.retrieveSettings(okapiParams); - - future.thenCompose(result -> { - context.assertEquals(result.getCurrency(), "EUR"); - context.assertEquals(result.getLocale(), "en-GB"); - context.assertEquals(result.getTimezone(), "UTC"); - async.complete(); - return null; - }).exceptionally(exception -> { - context.assertNull(exception); - async.complete(); - return null; - }); + var result = result(localeSettingsService.retrieveSettings(requestContext)); + + assertEquals("EUR", result.getCurrency()); + assertEquals("en-GB", result.getLocale()); + assertEquals("UTC", result.getTimezone()); } @Test - public void shouldReturnDefaultSettingsWhenResponseUnexpected(TestContext context) { - var async = context.async(); - var configFileName = "responses/configuration/locale-unexpected.json"; - mockSuccessfulLocaleResponse(configFileName); - - var future = localeSettingsService.retrieveSettings(okapiParams); - - future.thenCompose(result -> { - assertLocaleSettingsRecoveredToDefault(context, result); - async.complete(); - return null; - }).exceptionally(exception -> { - context.assertNull(exception); - async.complete(); - return null; - }); + void shouldReturnDefaultSettingsWhenResponseUnexpected() { + mockSuccessfulLocaleResponse("responses/configuration/locale-unexpected.json"); + + var result = result(localeSettingsService.retrieveSettings(requestContext)); + + assertDefaultLocaleSettings(result); } @Test - public void shouldReturnDefaultSettingsWhenConfigurationFailed(TestContext context) { - var async = context.async(); + void shouldReturnDefaultSettingsWhenConfigurationFailed() { mockFailedLocaleResponse(); - var future = localeSettingsService.retrieveSettings(okapiParams); - - future.thenCompose(result -> { - assertLocaleSettingsRecoveredToDefault(context, result); - async.complete(); - return null; - }).exceptionally(exception -> { - failTest(context); - async.complete(); - return null; - }); + + var result = result(localeSettingsService.retrieveSettings(requestContext)); + + assertDefaultLocaleSettings(result); } @Test - public void shouldReturnDefaultSettingsWhenResponseIsInvalidJson(TestContext context) { - var async = context.async(); + void shouldReturnDefaultSettingsWhenResponseIsInvalidJson() { mockLocaleResponseWithInvalidJson(); - var future = localeSettingsService.retrieveSettings(okapiParams); - - future.thenCompose(result -> { - assertLocaleSettingsRecoveredToDefault(context, result); - async.complete(); - return null; - }).exceptionally(exception -> { - failTest(context); - async.complete(); - return null; - }); + + var result = result(localeSettingsService.retrieveSettings(requestContext)); + + assertDefaultLocaleSettings(result); } @Test - public void shouldReturnDefaultSettingsWhenResponseIsEmpty(TestContext context) { - var async = context.async(); + void shouldReturnDefaultSettingsWhenResponseIsEmpty() { mockLocaleResponseWithEmptyBody(); - var future = localeSettingsService.retrieveSettings(okapiParams); - - future.thenCompose(result -> { - assertLocaleSettingsRecoveredToDefault(context, result); - async.complete(); - return null; - }).exceptionally(exception -> { - failTest(context); - async.complete(); - return null; - }); + + var result = result(localeSettingsService.retrieveSettings(requestContext)); + + assertDefaultLocaleSettings(result); } @Test - public void shouldReturnDefaultSettingsWhenServerError(TestContext context) { - var async = context.async(); + void shouldReturnDefaultSettingsWhenServerError() { mockLocaleResponseWithServerError(); - var future = localeSettingsService.retrieveSettings(okapiParams); - - future.thenCompose(result -> { - assertLocaleSettingsRecoveredToDefault(context, result); - async.complete(); - return null; - }).exceptionally(exception -> { - failTest(context); - async.complete(); - return null; - }); + + var result = result(localeSettingsService.retrieveSettings(requestContext)); + + assertDefaultLocaleSettings(result); } @Test - public void shouldReturnDefaultSettingsWhenNetworkFailure(TestContext context) { - var async = context.async(); + void shouldReturnDefaultSettingsWhenNetworkFailure() { mockLocaleResponseWithNetworkError(); - var future = localeSettingsService.retrieveSettings(okapiParams); - - future.thenCompose(result -> { - assertLocaleSettingsRecoveredToDefault(context, result); - async.complete(); - return null; - }).exceptionally(exception -> { - failTest(context); - async.complete(); - return null; - }); - } - private void failTest(TestContext context) { - context.fail("Should not complete exceptionally, but return default settings"); + var result = result(localeSettingsService.retrieveSettings(requestContext)); + + assertDefaultLocaleSettings(result); } - private void assertLocaleSettingsRecoveredToDefault(TestContext context, LocaleSettings result) { - context.assertEquals("USD", result.getCurrency()); - context.assertEquals("en-US", result.getLocale()); - context.assertEquals("UTC", result.getTimezone()); + private void assertDefaultLocaleSettings(LocaleSettings result) { + assertEquals("USD", result.getCurrency()); + assertEquals("en-US", result.getLocale()); + assertEquals("UTC", result.getTimezone()); } } diff --git a/src/test/java/org/folio/service/holdings/AbstractLoadServiceFacadeTest.java b/src/test/java/org/folio/service/holdings/AbstractLoadServiceFacadeTest.java index 1d6f4bd97..c514b0d5c 100644 --- a/src/test/java/org/folio/service/holdings/AbstractLoadServiceFacadeTest.java +++ b/src/test/java/org/folio/service/holdings/AbstractLoadServiceFacadeTest.java @@ -3,8 +3,8 @@ import static org.folio.repository.holdings.LoadStatus.COMPLETED; import static org.folio.repository.holdings.LoadStatus.IN_PROGRESS; import static org.folio.repository.holdings.LoadStatus.NONE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; @@ -18,15 +18,18 @@ import org.folio.holdingsiq.service.impl.LoadServiceImpl; import org.folio.repository.holdings.LoadStatus; import org.folio.service.holdings.message.LoadHoldingsMessage; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; import org.springframework.test.util.ReflectionTestUtils; -@RunWith(MockitoJUnitRunner.class) -public class AbstractLoadServiceFacadeTest { +@MockitoSettings(strictness = Strictness.WARN) +@ExtendWith(MockitoExtension.class) +class AbstractLoadServiceFacadeTest { private static final String TEST = "test"; @@ -65,7 +68,7 @@ protected int getMaxPageSize() { @Test @SneakyThrows - public void shouldRetryOnEmptyStatusFromHoldingsIq() { + void shouldRetryOnEmptyStatusFromHoldingsIq() { when(loadServiceFacadeSpy.getLastLoadingStatus(any())) .thenReturn(getHoldingsStatusFuture(getHoldingsStatus(NONE))); doReturn( @@ -88,7 +91,7 @@ public void shouldRetryOnEmptyStatusFromHoldingsIq() { @Test @SneakyThrows - public void shouldFailOnRetriesForLastStatusExceeded() { + void shouldFailOnRetriesForLastStatusExceeded() { when(loadServiceFacadeSpy.getLastLoadingStatus(any())) .thenReturn(getHoldingsStatusFuture(getHoldingsStatus(NONE))); doReturn( diff --git a/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java b/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java index 4b60f9ff1..ea1906ad2 100644 --- a/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java +++ b/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java @@ -4,39 +4,39 @@ import static org.folio.repository.holdings.LoadStatus.FAILED; import static org.folio.repository.holdings.LoadStatus.IN_PROGRESS; import static org.folio.repository.holdings.LoadStatus.NONE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.folio.util.TestUtil.result; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; import io.vertx.core.Vertx; import java.util.concurrent.CompletableFuture; import java.util.function.IntFunction; -import lombok.SneakyThrows; import org.folio.holdingsiq.model.HoldingsLoadStatus; import org.folio.holdingsiq.service.impl.LoadServiceImpl; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; -@RunWith(MockitoJUnitRunner.class) -public class DefaultLoadServiceFacadeTest { - - @Mock - private LoadServiceImpl loadService; +@MockitoSettings(strictness = Strictness.WARN) +@ExtendWith(MockitoExtension.class) +class DefaultLoadServiceFacadeTest { private final Vertx vertx = Vertx.vertx(); - private final int pageSize = 2500; private final int pageRetryCount = 3; - + @Mock + private LoadServiceImpl loadService; private DefaultLoadServiceFacade defaultLoadServiceFacade; - @Before - public void setUp() { + @BeforeEach + void setUp() { defaultLoadServiceFacade = new DefaultLoadServiceFacade( 1L, // statusRetryDelay 1, // statusRetryCount @@ -49,29 +49,27 @@ public void setUp() { } @Test - @SneakyThrows - public void shouldNotFailOnEmptyStatusFromHoldingsIq() { - Mockito.when(loadService.getLoadingStatus()) + void shouldNotFailOnEmptyStatusFromHoldingsIq() { + when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(null)); - var result = defaultLoadServiceFacade.getLastLoadingStatus(loadService); - assertEquals(NONE, result.get().getStatus()); + var result = result(defaultLoadServiceFacade.getLastLoadingStatus(loadService)); + + assertEquals(NONE, result.getStatus()); } @Test - @SneakyThrows - public void shouldMapLoadStatusCompletedCorrectly() { - HoldingsLoadStatus holdingsLoadStatus = HoldingsLoadStatus.builder() + void shouldMapLoadStatusCompletedCorrectly() { + var holdingsLoadStatus = HoldingsLoadStatus.builder() .status("Completed") .created("2024-01-01 10:00:00") .totalCount(5000) .build(); - Mockito.when(loadService.getLoadingStatus()) + when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(holdingsLoadStatus)); - var result = defaultLoadServiceFacade.getLastLoadingStatus(loadService); - HoldingsStatus holdingsStatus = result.get(); + var holdingsStatus = result(defaultLoadServiceFacade.getLastLoadingStatus(loadService)); assertEquals(COMPLETED, holdingsStatus.getStatus()); assertEquals("2024-01-01 10:00:00", holdingsStatus.getCreated()); @@ -79,19 +77,17 @@ public void shouldMapLoadStatusCompletedCorrectly() { } @Test - @SneakyThrows - public void shouldMapLoadStatusInProgressCorrectly() { - HoldingsLoadStatus holdingsLoadStatus = HoldingsLoadStatus.builder() + void shouldMapLoadStatusInProgressCorrectly() { + var holdingsLoadStatus = HoldingsLoadStatus.builder() .status("In progress") .created("2024-01-01 09:00:00") .totalCount(3000) .build(); - Mockito.when(loadService.getLoadingStatus()) + when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(holdingsLoadStatus)); - var result = defaultLoadServiceFacade.getLastLoadingStatus(loadService); - HoldingsStatus holdingsStatus = result.get(); + var holdingsStatus = result(defaultLoadServiceFacade.getLastLoadingStatus(loadService)); assertEquals(IN_PROGRESS, holdingsStatus.getStatus()); assertEquals("2024-01-01 09:00:00", holdingsStatus.getCreated()); @@ -99,19 +95,17 @@ public void shouldMapLoadStatusInProgressCorrectly() { } @Test - @SneakyThrows - public void shouldMapLoadStatusFailedCorrectly() { - HoldingsLoadStatus holdingsLoadStatus = HoldingsLoadStatus.builder() + void shouldMapLoadStatusFailedCorrectly() { + var holdingsLoadStatus = HoldingsLoadStatus.builder() .status("Failed") .created("2024-01-01 08:00:00") .totalCount(0) .build(); - Mockito.when(loadService.getLoadingStatus()) + when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(holdingsLoadStatus)); - var result = defaultLoadServiceFacade.getLastLoadingStatus(loadService); - HoldingsStatus holdingsStatus = result.get(); + var holdingsStatus = result(defaultLoadServiceFacade.getLastLoadingStatus(loadService)); assertEquals(FAILED, holdingsStatus.getStatus()); assertEquals("2024-01-01 08:00:00", holdingsStatus.getCreated()); @@ -119,71 +113,54 @@ public void shouldMapLoadStatusFailedCorrectly() { } @Test - @SneakyThrows - public void shouldGetLoadingStatusReturnLastLoadingStatusIgnoringTransactionId() { - HoldingsLoadStatus holdingsLoadStatus = HoldingsLoadStatus.builder() + void shouldGetLoadingStatusReturnLastLoadingStatusIgnoringTransactionId() { + var holdingsLoadStatus = HoldingsLoadStatus.builder() .status("Completed") .created("2024-01-01 10:00:00") .totalCount(5000) .build(); - Mockito.when(loadService.getLoadingStatus()) + when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(holdingsLoadStatus)); - var result = defaultLoadServiceFacade.getLoadingStatus(loadService, "tx-123"); - HoldingsStatus holdingsStatus = result.get(); + var holdingsStatus = result(defaultLoadServiceFacade.getLoadingStatus(loadService, "tx-123")); assertEquals(COMPLETED, holdingsStatus.getStatus()); assertEquals(Integer.valueOf(5000), holdingsStatus.getTotalCount()); } @Test - public void shouldGetMaxPageSizeReturnConfiguredPageSize() { + void shouldGetMaxPageSizeReturnConfiguredPageSize() { assertEquals(pageSize, defaultLoadServiceFacade.getMaxPageSize()); } @Test - @SneakyThrows - public void shouldCalculateOffsetForPages() { + void shouldCalculateOffsetForPages() { verifyOffset(1, 1); verifyOffset(2, 2501); verifyOffset(3, 5001); } - private void verifyOffset(int pageNumber, int expectedOffset) { - CompletableFuture<Void> callbackFuture = CompletableFuture.completedFuture(null); - IntFunction<CompletableFuture<Void>> offsetLoader = offset -> { - assertEquals(expectedOffset, offset); - return callbackFuture; - }; - - defaultLoadServiceFacade.calculateOffset(offsetLoader, pageNumber, pageRetryCount); - - assertTrue(callbackFuture.isDone()); - } - @Test - @SneakyThrows - public void shouldPopulateHoldingsReturnNullTransactionId() { - Mockito.when(loadService.populateHoldingsForce()) + void shouldPopulateHoldingsReturnNullTransactionId() { + when(loadService.populateHoldingsForce()) .thenReturn(CompletableFuture.completedFuture(null)); - var result = defaultLoadServiceFacade.populateHoldings(loadService); - assertNull(result.get()); + var actual = result(defaultLoadServiceFacade.populateHoldings(loadService)); + + assertNull(actual); } @Test - @SneakyThrows - public void shouldGetLastLoadingStatusWithDefaultValues() { - HoldingsLoadStatus holdingsLoadStatus = HoldingsLoadStatus.builder() + void shouldGetLastLoadingStatusWithDefaultValues() { + var holdingsLoadStatus = HoldingsLoadStatus.builder() .status("Completed") .build(); - Mockito.when(loadService.getLoadingStatus()) + when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(holdingsLoadStatus)); - var result = defaultLoadServiceFacade.getLastLoadingStatus(loadService); - HoldingsStatus holdingsStatus = result.get(); + var holdingsStatus = result(defaultLoadServiceFacade.getLastLoadingStatus(loadService)); assertEquals(COMPLETED, holdingsStatus.getStatus()); assertNull(holdingsStatus.getCreated()); @@ -191,23 +168,33 @@ public void shouldGetLastLoadingStatusWithDefaultValues() { } @Test - @SneakyThrows - public void shouldGetLastLoadingStatusPreserveCreatedAndCount() { - HoldingsLoadStatus holdingsLoadStatus = HoldingsLoadStatus.builder() + void shouldGetLastLoadingStatusPreserveCreatedAndCount() { + var holdingsLoadStatus = HoldingsLoadStatus.builder() .status("Completed") .created("2024-01-01 10:00:00") .totalCount(5000) .build(); - Mockito.when(loadService.getLoadingStatus()) + when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(holdingsLoadStatus)); - var result = defaultLoadServiceFacade.getLastLoadingStatus(loadService); - HoldingsStatus holdingsStatus = result.get(); + var holdingsStatus = result(defaultLoadServiceFacade.getLastLoadingStatus(loadService)); assertNotNull(holdingsStatus); assertEquals(COMPLETED, holdingsStatus.getStatus()); assertEquals("2024-01-01 10:00:00", holdingsStatus.getCreated()); assertEquals(Integer.valueOf(5000), holdingsStatus.getTotalCount()); } + + private void verifyOffset(int pageNumber, int expectedOffset) { + var callbackFuture = CompletableFuture.<Void>completedFuture(null); + IntFunction<CompletableFuture<Void>> offsetLoader = offset -> { + assertEquals(expectedOffset, offset); + return callbackFuture; + }; + + defaultLoadServiceFacade.calculateOffset(offsetLoader, pageNumber, pageRetryCount); + + assertTrue(callbackFuture.isDone()); + } } diff --git a/src/test/java/org/folio/service/uc/UcAuthServiceImplTest.java b/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java similarity index 51% rename from src/test/java/org/folio/service/uc/UcAuthServiceImplTest.java rename to src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java index a109d16bc..ca59549cc 100644 --- a/src/test/java/org/folio/service/uc/UcAuthServiceImplTest.java +++ b/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java @@ -1,22 +1,21 @@ package org.folio.service.uc; import static io.vertx.core.Future.succeededFuture; -import static org.apache.http.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_OK; import static org.folio.repository.uc.UcCredentialsTableConstants.UC_CREDENTIALS_TABLE_NAME; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.util.KbTestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.folio.util.TestUtil.result; import static org.folio.util.UcCredentialsTestUtil.setUpUcCredentials; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.openMocks; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; import io.vertx.ext.web.client.HttpRequest; import io.vertx.ext.web.client.HttpResponse; import io.vertx.ext.web.client.WebClient; @@ -26,20 +25,26 @@ import org.folio.client.uc.UcAuthEbscoClient; import org.folio.client.uc.model.UcAuthToken; import org.folio.okapi.common.XOkapiHeaders; -import org.folio.rest.impl.WireMockTestBase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.folio.util.IntegrationTestBase; +import org.folio.util.TestFutureFailedException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.util.ReflectionTestUtils; -@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -@RunWith(VertxUnitRunner.class) -public class UcAuthServiceImplTest extends WireMockTestBase { +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class UcAuthServiceImplIntegrationTest extends IntegrationTestBase { + + private static final CaseInsensitiveMap<String, String> HEADERS = + new CaseInsensitiveMap<>(Map.of(XOkapiHeaders.TENANT, STUB_TENANT)); - public static final int TIMEOUT = 100000; @Autowired private UcAuthService ucAuthService; @Autowired @@ -53,11 +58,8 @@ public class UcAuthServiceImplTest extends WireMockTestBase { @Spy private HttpRequest<JsonObject> jsonHttpRequest; - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - openMocks(this).close(); + @BeforeEach + void beforeEach() { ReflectionTestUtils.setField(authServiceClient, "webClient", client); when(client.postAbs(anyString())).thenReturn(httpRequest); @@ -66,42 +68,29 @@ public void setUp() throws Exception { when(httpRequest.as(BodyCodec.jsonObject())).thenReturn(jsonHttpRequest); } - @After - public void tearDown() { + @AfterEach + void tearDown() { clearDataFromTable(vertx, UC_CREDENTIALS_TABLE_NAME); } @Test - public void returnTokenWhenCredentialsValid(TestContext context) { - UcAuthToken mockedToken = new UcAuthToken("access-token", "token-type", 1000L, "scope"); + void returnTokenWhenCredentialsValid() { + var mockedToken = new UcAuthToken("access-token", "token-type", 1000L, "scope"); when(httpResponse.statusCode()).thenReturn(SC_OK); when(httpResponse.body()).thenReturn(JsonObject.mapFrom(mockedToken)); setUpUcCredentials(vertx); - Async async = context.async(); - ucAuthService.authenticate(new CaseInsensitiveMap<>(Map.of(XOkapiHeaders.TENANT, STUB_TENANT))) - .thenAccept(expected -> { - context.assertEquals(expected, mockedToken.accessToken()); - async.complete(); - }) - .exceptionally(throwable -> { - context.fail(throwable); - async.complete(); - return null; - }); - async.await(TIMEOUT); + var result = result(ucAuthService.authenticate(HEADERS)); + + assertEquals(mockedToken.accessToken(), result); } @Test - public void returnTokenWhenCredentialsAreNotExist(TestContext context) { - Async async = context.async(); - ucAuthService.authenticate(new CaseInsensitiveMap<>(Map.of(XOkapiHeaders.TENANT, STUB_TENANT))) - .exceptionally(throwable -> { - context.assertEquals(UcAuthenticationException.class, throwable.getCause().getClass()); - async.complete(); - return null; - }); - async.await(TIMEOUT); + void returnTokenWhenCredentialsAreNotExist() { + var authResult = ucAuthService.authenticate(HEADERS); + var ex = assertThrows(TestFutureFailedException.class, () -> result(authResult)); + + assertEquals(UcAuthenticationException.class, ex.getCause().getClass()); } } diff --git a/src/test/java/org/folio/service/users/UsersLookUpServiceTest.java b/src/test/java/org/folio/service/users/UsersLookUpServiceTest.java index d59c1fe15..84e748b24 100644 --- a/src/test/java/org/folio/service/users/UsersLookUpServiceTest.java +++ b/src/test/java/org/folio/service/users/UsersLookUpServiceTest.java @@ -1,266 +1,114 @@ package org.folio.service.users; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static org.folio.rest.impl.WireMockTestBase.JANE_GROUP_ID; -import static org.folio.rest.impl.WireMockTestBase.JANE_ID; -import static org.folio.rest.impl.WireMockTestBase.JOHN_GROUP_ID; -import static org.folio.rest.impl.WireMockTestBase.JOHN_ID; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.service.users.UsersLookUpService.USERS_BY_ID_ENDPOINT; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.result; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.common.Slf4jNotifier; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.junit.WireMockRule; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; import io.vertx.core.Vertx; -import io.vertx.ext.unit.Async; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.NotFoundException; -import org.folio.common.OkapiParams; +import org.folio.holdingsiq.model.RequestContext; import org.folio.okapi.common.XOkapiHeaders; -import org.folio.test.junit.TestStartLoggingRule; -import org.folio.test.util.TestUtil; -import org.folio.util.StringUtil; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; +import org.folio.util.TestFutureFailedException; +import org.folio.util.WireMockTestBase; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; -@RunWith(VertxUnitRunner.class) -public class UsersLookUpServiceTest { +class UsersLookUpServiceTest extends WireMockTestBase { - private static final String HOST = "http://127.0.0.1"; - private static final String STUB_PATH = "responses/userlookup/"; - private static final String USER_INFO_STUB_FILE = STUB_PATH + "mock_user_response_200.json"; - private static final String GROUP_INFO_STUB_FILE = STUB_PATH + "mock_group_collection_response_200.json"; - private static final String USERDATA_COLLECTION_INFO_STUB_FILE = STUB_PATH + "mock_user_collection_response_200.json"; + private static Map<String, String> defaultHeaders; + private static RequestContext requestContext; - private static final String GET_USER_ENDPOINT = "/users/"; - private static final String QUERY_PARAM = "query"; - private static final Map<String, String> OKAPI_HEADERS = new HashMap<>(); - @Rule - public TestRule watcher = TestStartLoggingRule.instance(); - @Rule - public WireMockRule userMockServer = - new WireMockRule(WireMockConfiguration.wireMockConfig().dynamicPort().notifier(new Slf4jNotifier(true))); private final UsersLookUpService usersLookUpService = new UsersLookUpService(Vertx.vertx()); - @Test - public void shouldReturn200WhenThirdPartyUserIdIsValid(TestContext context) throws IOException, URISyntaxException { - final String stubUserId = "88888888-8888-4888-8888-888888888888"; - final String stubUserIdEndpoint = GET_USER_ENDPOINT + stubUserId; - - OKAPI_HEADERS.put(XOkapiHeaders.TENANT, STUB_TENANT); - OKAPI_HEADERS.put(XOkapiHeaders.URL, getWiremockUrl()); - - stubFor(get(new UrlPathPattern(new RegexPattern(stubUserIdEndpoint), true)).willReturn( - new ResponseDefinitionBuilder().withBody(TestUtil.readFile(USER_INFO_STUB_FILE)))); - - Async async = context.async(); - CompletableFuture<User> info = usersLookUpService.lookUpUserById(stubUserId, new OkapiParams(OKAPI_HEADERS)); - info.thenCompose(userInfo -> { - context.assertNotNull(userInfo); - - context.assertEquals("cedrick", userInfo.getUserName()); - context.assertEquals("firstname_test", userInfo.getFirstName()); - context.assertNull(userInfo.getMiddleName()); - context.assertEquals("lastname_test", userInfo.getLastName()); - - async.complete(); - - return null; - }).exceptionally(throwable -> { - context.fail(throwable); - async.complete(); - return null; - }); + @BeforeAll + static void beforeAll() { + defaultHeaders = Map.of( + XOkapiHeaders.TENANT, STUB_TENANT, + XOkapiHeaders.USER_ID, USER_1, + XOkapiHeaders.URL, wm.baseUrl() + ); + requestContext = new RequestContext(defaultHeaders); } @Test - public void shouldReturn200WhenUserIdIsValid(TestContext context) throws IOException, URISyntaxException { - final String stubUserId = "88888888-8888-4888-8888-888888888888"; - final String stubUserIdEndpoint = GET_USER_ENDPOINT + stubUserId; - - OKAPI_HEADERS.put(XOkapiHeaders.TENANT, STUB_TENANT); - OKAPI_HEADERS.put(XOkapiHeaders.URL, getWiremockUrl()); - OKAPI_HEADERS.put(XOkapiHeaders.USER_ID, stubUserId); - - stubFor(get(new UrlPathPattern(new RegexPattern(stubUserIdEndpoint), true)).willReturn( - new ResponseDefinitionBuilder().withBody(TestUtil.readFile(USER_INFO_STUB_FILE)))); - - Async async = context.async(); - CompletableFuture<User> info = usersLookUpService.lookUpUser(new OkapiParams(OKAPI_HEADERS)); - info.thenCompose(userInfo -> { - context.assertNotNull(userInfo); - - context.assertEquals("cedrick", userInfo.getUserName()); - context.assertEquals("firstname_test", userInfo.getFirstName()); - context.assertNull(userInfo.getMiddleName()); - context.assertEquals("lastname_test", userInfo.getLastName()); - - async.complete(); - - return null; - }).exceptionally(throwable -> { - context.fail(throwable); - async.complete(); - return null; - }); + void shouldReturn200WhenThirdPartyUserIdIsValid() { + var userInfo = result(usersLookUpService.lookUpUserById(USER_1, requestContext)); + assertUserInfo(userInfo); } @Test - public void shouldReturnUsersWithStatus200ByCqlUserIdList(TestContext context) - throws IOException, URISyntaxException { - final UUID janeId = UUID.fromString(JANE_ID); - final UUID johnId = UUID.fromString(JOHN_ID); - - List<UUID> ids = List.of(janeId, johnId); - - String query = cqlQueryConverter(ids); - - OKAPI_HEADERS.put(XOkapiHeaders.TENANT, STUB_TENANT); - OKAPI_HEADERS.put(XOkapiHeaders.URL, getWiremockUrl()); - - stubFor(get(new UrlPathPattern(new RegexPattern("/users"), true)).withQueryParam(QUERY_PARAM, equalTo(query)) - .willReturn(new ResponseDefinitionBuilder().withBody(TestUtil.readFile(USERDATA_COLLECTION_INFO_STUB_FILE)))); - - Async async = context.async(); - CompletableFuture<List<User>> info = usersLookUpService.lookUpUsers(ids, new OkapiParams(OKAPI_HEADERS)); - info.thenCompose(userInfo -> { - context.assertNotNull(userInfo); - context.assertEquals(2, userInfo.size()); - async.complete(); - - return null; - }).exceptionally(throwable -> { - context.fail(throwable); - async.complete(); - return null; - }); + void shouldReturn200WhenUserIdIsValid() { + var userInfo = result(usersLookUpService.lookUpUser(requestContext)); + assertUserInfo(userInfo); } @Test - public void shouldReturn200WhenGroupIdIsValid(TestContext context) throws IOException, URISyntaxException { - final UUID groupId1 = UUID.fromString(JOHN_GROUP_ID); - final UUID groupId2 = UUID.fromString(JANE_GROUP_ID); - - List<UUID> ids = List.of(groupId1, groupId2); - String cqlQuery = cqlQueryConverter(ids); - - OKAPI_HEADERS.put(XOkapiHeaders.TENANT, STUB_TENANT); - OKAPI_HEADERS.put(XOkapiHeaders.URL, getWiremockUrl()); + void shouldReturn200ByCqlUserIdList() { + var ids = List.of(UUID.fromString(JANE_ID), UUID.fromString(JOHN_ID)); - stubFor(get(new UrlPathPattern(new RegexPattern("/groups"), true)).withQueryParam(QUERY_PARAM, equalTo(cqlQuery)) - .willReturn(new ResponseDefinitionBuilder().withBody(TestUtil.readFile(GROUP_INFO_STUB_FILE)))); - - Async async = context.async(); - CompletableFuture<List<Group>> info = usersLookUpService.lookUpGroups(ids, new OkapiParams(OKAPI_HEADERS)); - info.thenCompose(group -> { - context.assertNotNull(group); - context.assertEquals(2, group.size()); - async.complete(); - - return null; - }).exceptionally(throwable -> { - context.fail(throwable); - async.complete(); - return null; - }); + var userInfo = result(usersLookUpService.lookUpUsers(ids, requestContext)); + assertNotNull(userInfo); + assertEquals(2, userInfo.size()); } @Test - public void shouldReturn401WhenUnauthorizedAccess(TestContext context) { - final String stubUserId = "a49cefad-7447-4f2f-9004-de32e7a6cc53"; - final String stubUserIdEndpoint = GET_USER_ENDPOINT + stubUserId; - - OKAPI_HEADERS.put(XOkapiHeaders.URL, getWiremockUrl()); - OKAPI_HEADERS.put(XOkapiHeaders.USER_ID, stubUserId); - - stubFor(get(new UrlPathPattern(new RegexPattern(stubUserIdEndpoint), true)).willReturn( - new ResponseDefinitionBuilder().withStatus(401).withStatusMessage("Authorization Failure"))); + void shouldReturn200WhenGroupIdIsValid() { + var ids = List.of(UUID.fromString(JOHN_GROUP_ID), UUID.fromString(JANE_GROUP_ID)); - Async async = context.async(); - CompletableFuture<User> info = usersLookUpService.lookUpUser(new OkapiParams(OKAPI_HEADERS)); - info.thenCompose(result -> { - context.assertNull(result); - async.complete(); - return null; - }).exceptionally(exception -> { - context.assertTrue(exception.getCause() instanceof NotAuthorizedException); - async.complete(); - return null; - }); + var group = result(usersLookUpService.lookUpGroups(ids, requestContext)); + assertNotNull(group); + assertEquals(2, group.size()); } @Test - public void shouldReturn404WhenUserNotFound(TestContext context) { - final String stubUserId = "xyz"; - final String stubUserIdEndpoint = GET_USER_ENDPOINT + stubUserId; - - OKAPI_HEADERS.put(XOkapiHeaders.TENANT, STUB_TENANT); - OKAPI_HEADERS.put(XOkapiHeaders.URL, getWiremockUrl()); - OKAPI_HEADERS.put(XOkapiHeaders.USER_ID, stubUserId); + void shouldReturn401WhenUnauthorizedAccess() { + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(USER_1)), SC_UNAUTHORIZED); - stubFor(get(new UrlPathPattern(new RegexPattern(stubUserIdEndpoint), true)).willReturn( - new ResponseDefinitionBuilder().withStatus(404).withStatusMessage("User Not Found"))); + var lookupFuture = usersLookUpService.lookUpUser(requestContext); + var ex = assertThrows(TestFutureFailedException.class, () -> result(lookupFuture)); + assertInstanceOf(NotAuthorizedException.class, ex.getCause()); + } - Async async = context.async(); - CompletableFuture<User> info = usersLookUpService.lookUpUser(new OkapiParams(OKAPI_HEADERS)); - info.thenCompose(result -> { - context.assertNull(result); - async.complete(); - return null; - }).exceptionally(exception -> { - context.assertTrue(exception.getCause() instanceof NotFoundException); - async.complete(); - return null; - }); + @Test + void shouldReturn404WhenUserNotFound() { + var stubUserId = "xyz"; + var headers = new HashMap<>(defaultHeaders); + headers.put(XOkapiHeaders.USER_ID, stubUserId); + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(stubUserId)), SC_NOT_FOUND); + + var lookupFuture = usersLookUpService.lookUpUser(new RequestContext(headers)); + var ex = assertThrows(TestFutureFailedException.class, () -> result(lookupFuture)); + assertInstanceOf(NotFoundException.class, ex.getCause()); } @Test - public void shouldReturn404WhenUserNotFoundById(TestContext context) { + void shouldReturn404WhenUserNotFoundById() { final String stubUserId = "xyz"; - final String stubUserIdEndpoint = GET_USER_ENDPOINT + stubUserId; - - OKAPI_HEADERS.put(XOkapiHeaders.TENANT, STUB_TENANT); - OKAPI_HEADERS.put(XOkapiHeaders.URL, getWiremockUrl()); - OKAPI_HEADERS.put(XOkapiHeaders.USER_ID, stubUserId); - - stubFor(get(new UrlPathPattern(new RegexPattern(stubUserIdEndpoint), true)).willReturn( - new ResponseDefinitionBuilder().withStatus(404).withStatusMessage("User Not Found"))); - - Async async = context.async(); - CompletableFuture<User> info = usersLookUpService.lookUpUserById(stubUserId, new OkapiParams(OKAPI_HEADERS)); - info.thenCompose(result -> { - context.fail("Must fail with NotFoundException"); - async.complete(); - return null; - }).exceptionally(exception -> { - context.assertTrue(exception.getCause() instanceof NotFoundException); - async.complete(); - return null; - }); - } + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(stubUserId)), SC_NOT_FOUND); - private String cqlQueryConverter(List<UUID> ids) { - return "id=(" + ids.stream().map(UUID::toString).map(StringUtil::cqlEncode) - .collect(Collectors.joining(" OR ")) + ")"; + var lookupFuture = usersLookUpService.lookUpUserById(stubUserId, requestContext); + var ex = assertThrows(TestFutureFailedException.class, () -> result(lookupFuture)); + assertInstanceOf(NotFoundException.class, ex.getCause()); } - private String getWiremockUrl() { - return HOST + ":" + userMockServer.port(); + private void assertUserInfo(User userInfo) { + assertNotNull(userInfo); + assertEquals("cedrick", userInfo.getUserName()); + assertEquals("firstname_test", userInfo.getFirstName()); + assertNull(userInfo.getMiddleName()); + assertEquals("lastname_test", userInfo.getLastName()); } } diff --git a/src/test/java/org/folio/util/AccessTypesTestUtil.java b/src/test/java/org/folio/util/AccessTypesTestUtil.java index 2ede026bd..e18da156c 100644 --- a/src/test/java/org/folio/util/AccessTypesTestUtil.java +++ b/src/test/java/org/folio/util/AccessTypesTestUtil.java @@ -20,9 +20,9 @@ import static org.folio.repository.accesstypes.AccessTypesTableConstants.NAME_COLUMN; import static org.folio.repository.accesstypes.AccessTypesTableConstants.USAGE_NUMBER_COLUMN; import static org.folio.repository.accesstypes.AccessTypesTableConstants.upsertAccessTypeQuery; -import static org.folio.rest.impl.WireMockTestBase.JOHN_ID; -import static org.folio.test.util.TestUtil.STUB_TENANT; import static org.folio.util.KbCredentialsTestUtil.KB_CREDENTIALS_ENDPOINT; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.WireMockTestBase.JOHN_ID; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; @@ -34,6 +34,7 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.apache.commons.lang3.ObjectUtils; import org.folio.db.DbUtils; import org.folio.repository.RecordType; @@ -47,6 +48,7 @@ import org.folio.rest.persist.PostgresClient; import org.springframework.core.convert.converter.Converter; +@UtilityClass public class AccessTypesTestUtil { public static final String STUB_ACCESS_TYPE_NAME = "Subscribed"; @@ -116,6 +118,17 @@ public static List<AccessType> getAccessTypes(Vertx vertx) { return future.join(); } + public static List<AccessType> testData() { + return testData(null); + } + + public static List<AccessType> testData(String credentialsId) { + var accessType1 = getAccessType(credentialsId, STUB_ACCESS_TYPE_NAME, "Access Type description 1"); + var accessType2 = getAccessType(credentialsId, STUB_ACCESS_TYPE_NAME_2, "Access Type description 2"); + var accessType3 = getAccessType(credentialsId, STUB_ACCESS_TYPE_NAME_3, "Access Type description 3"); + return Arrays.asList(accessType1, accessType2, accessType3); + } + private static AccessTypeMapping mapAccessTypeMapping(Row entry) { return AccessTypeMapping.builder() .id(entry.getUUID(ID_COLUMN)) @@ -139,17 +152,6 @@ private static AccessType mapAccessType(Row resultRow) { .build()); } - public static List<AccessType> testData() { - return testData(null); - } - - public static List<AccessType> testData(String credentialsId) { - var accessType1 = getAccessType(credentialsId, STUB_ACCESS_TYPE_NAME, "Access Type description 1"); - var accessType2 = getAccessType(credentialsId, STUB_ACCESS_TYPE_NAME_2, "Access Type description 2"); - var accessType3 = getAccessType(credentialsId, STUB_ACCESS_TYPE_NAME_3, "Access Type description 3"); - return Arrays.asList(accessType1, accessType2, accessType3); - } - private static AccessType getAccessType(String credentialsId, String name, String description) { return new AccessType() .withType(AccessType.Type.ACCESS_TYPES) diff --git a/src/test/java/org/folio/util/AssertTestUtil.java b/src/test/java/org/folio/util/AssertTestUtil.java index 0dcc7bb2f..b583d5baf 100644 --- a/src/test/java/org/folio/util/AssertTestUtil.java +++ b/src/test/java/org/folio/util/AssertTestUtil.java @@ -1,35 +1,34 @@ package org.folio.util; -import static org.folio.rest.impl.PackagesTestData.FULL_PACKAGE_ID; -import static org.folio.rest.impl.ResourcesTestData.STUB_CUSTOM_RESOURCE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_CUSTOM_TITLE_ID; +import static org.folio.util.RmApiConstants.CUSTOM_TITLE_ID; +import static org.folio.util.RmApiConstants.FULL_PACKAGE_ID; +import static org.folio.util.RmApiConstants.STUB_CUSTOM_RESOURCE_ID; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.UUID; +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; import org.folio.holdingsiq.model.PackageId; import org.folio.holdingsiq.model.ResourceId; import org.folio.rest.jaxrs.model.JsonapiError; import org.folio.rest.util.IdParser; -import org.junit.Assert; +import org.skyscreamer.jsonassert.JSONAssert; +@UtilityClass public final class AssertTestUtil { - private AssertTestUtil() { - } - public static void assertEqualsUuid(String string, UUID uuid) { assertEquals(string, uuid.toString()); } public static void assertEqualsLong(Long l) { - assertEquals(STUB_CUSTOM_TITLE_ID, String.valueOf(l)); + assertEquals(CUSTOM_TITLE_ID, l); } public static void assertEqualsPackageId(PackageId id) { - Assert.assertEquals(FULL_PACKAGE_ID, IdParser.packageIdToString(id)); + assertEquals(FULL_PACKAGE_ID, IdParser.packageIdToString(id)); } public static void assertEqualsResourceId(ResourceId id) { @@ -37,12 +36,22 @@ public static void assertEqualsResourceId(ResourceId id) { } public static void assertErrorContainsTitle(JsonapiError error, String substring) { - assertThat(error.getErrors(), hasSize(1)); + assertEquals(1, error.getErrors().size()); assertThat(error.getErrors().getFirst().getTitle(), containsString(substring)); } public static void assertErrorContainsDetail(JsonapiError error, String substring) { - assertThat(error.getErrors(), hasSize(1)); + assertEquals(1, error.getErrors().size()); assertThat(error.getErrors().getFirst().getDetail(), containsString(substring)); } + + @SneakyThrows + public static void assertJsonEqual(String expected, String actual) { + JSONAssert.assertEquals(expected, actual, false); + } + + @SneakyThrows + public static void assertJsonEqual(String expected, String actual, boolean strict) { + JSONAssert.assertEquals(expected, actual, strict); + } } diff --git a/src/test/java/org/folio/util/AssignedUsersTestUtil.java b/src/test/java/org/folio/util/AssignedUsersTestUtil.java index 4d6f8a4de..1a31cb24d 100644 --- a/src/test/java/org/folio/util/AssignedUsersTestUtil.java +++ b/src/test/java/org/folio/util/AssignedUsersTestUtil.java @@ -5,7 +5,7 @@ import static org.folio.repository.assigneduser.AssignedUsersConstants.CREDENTIALS_ID_COLUMN; import static org.folio.repository.assigneduser.AssignedUsersConstants.ID_COLUMN; import static org.folio.repository.assigneduser.AssignedUsersConstants.insertAssignedUserQuery; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; @@ -13,6 +13,7 @@ import io.vertx.sqlclient.Tuple; import java.util.List; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.db.DbUtils; import org.folio.db.RowSetUtils; import org.folio.repository.DbUtil; @@ -23,6 +24,7 @@ import org.folio.rest.persist.PostgresClient; import org.springframework.core.convert.converter.Converter; +@UtilityClass public class AssignedUsersTestUtil { private static final Converter<DbAssignedUser, AssignedUser> CONVERTER = diff --git a/src/test/java/org/folio/util/HoldingsRetryStatusTestUtil.java b/src/test/java/org/folio/util/HoldingsRetryStatusTestUtil.java index 77433f4fd..57e86d280 100644 --- a/src/test/java/org/folio/util/HoldingsRetryStatusTestUtil.java +++ b/src/test/java/org/folio/util/HoldingsRetryStatusTestUtil.java @@ -10,16 +10,18 @@ import static org.folio.repository.holdings.status.retry.RetryStatusTableConstants.RETRY_STATUS_TABLE; import static org.folio.repository.holdings.status.retry.RetryStatusTableConstants.TIMER_ID_COLUMN; import static org.folio.repository.holdings.status.retry.RetryStatusTableConstants.getRetryStatusByCredentials; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Tuple; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.repository.holdings.status.retry.RetryStatus; import org.folio.rest.persist.PostgresClient; +@UtilityClass public class HoldingsRetryStatusTestUtil { public static RetryStatus insertRetryStatus(String credentialsId, Vertx vertx) { diff --git a/src/test/java/org/folio/util/HoldingsStatusAuditTestUtil.java b/src/test/java/org/folio/util/HoldingsStatusAuditTestUtil.java index 2075eaac4..1cf27d828 100644 --- a/src/test/java/org/folio/util/HoldingsStatusAuditTestUtil.java +++ b/src/test/java/org/folio/util/HoldingsStatusAuditTestUtil.java @@ -12,7 +12,7 @@ import static org.folio.repository.holdings.status.audit.HoldingsStatusAuditTableConstants.JSONB_COLUMN; import static org.folio.repository.holdings.status.audit.HoldingsStatusAuditTableConstants.OPERATION_COLUMN; import static org.folio.repository.holdings.status.audit.HoldingsStatusAuditTableConstants.UPDATED_AT_COLUMN; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; @@ -21,9 +21,11 @@ import java.time.OffsetDateTime; import java.util.List; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.rest.jaxrs.model.HoldingsLoadingStatus; import org.folio.rest.persist.PostgresClient; +@UtilityClass public class HoldingsStatusAuditTestUtil { public static List<HoldingsLoadingStatus> getRecords(Vertx vertx) { diff --git a/src/test/java/org/folio/util/HoldingsStatusUtil.java b/src/test/java/org/folio/util/HoldingsStatusUtil.java index bff6e0b68..2b3109f42 100644 --- a/src/test/java/org/folio/util/HoldingsStatusUtil.java +++ b/src/test/java/org/folio/util/HoldingsStatusUtil.java @@ -10,19 +10,20 @@ import static org.folio.repository.holdings.status.HoldingsStatusTableConstants.JSONB_COLUMN; import static org.folio.repository.holdings.status.HoldingsStatusTableConstants.getHoldingsStatusById; import static org.folio.repository.holdings.status.HoldingsStatusTableConstants.insertLoadingStatus; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.core.json.Json; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; import io.vertx.sqlclient.Tuple; -import java.time.OffsetDateTime; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.repository.DbUtil; import org.folio.rest.jaxrs.model.HoldingsLoadingStatus; import org.folio.rest.persist.PostgresClient; +@UtilityClass public class HoldingsStatusUtil { public static final String PROCESS_ID = "926223cc-bd21-4fe2-af75-b8e82cfecad3"; @@ -32,7 +33,7 @@ public static HoldingsLoadingStatus saveStatusNotStarted(String credentialsId, V } public static HoldingsLoadingStatus saveStatus(String credentialsId, HoldingsLoadingStatus status, String processId, - OffsetDateTime startedTime, Vertx vertx) { + Vertx vertx) { CompletableFuture<HoldingsLoadingStatus> future = new CompletableFuture<>(); String query = DbUtil.prepareQuery(insertLoadingStatus(), holdingsStatusTestTable(), createPlaceholders(4)); Tuple params = Tuple.of(randomUUID(), toUUID(credentialsId), toJsonObject(status), toUUID(processId)); @@ -40,11 +41,6 @@ public static HoldingsLoadingStatus saveStatus(String credentialsId, HoldingsLoa return future.join(); } - public static HoldingsLoadingStatus saveStatus(String credentialsId, HoldingsLoadingStatus status, String processId, - Vertx vertx) { - return saveStatus(credentialsId, status, processId, OffsetDateTime.now(), vertx); - } - public static HoldingsLoadingStatus getStatus(String credentialsId, Vertx vertx) { CompletableFuture<HoldingsLoadingStatus> future = new CompletableFuture<>(); String query = DbUtil.prepareQuery(getHoldingsStatusById(), holdingsStatusTestTable()); diff --git a/src/test/java/org/folio/util/HoldingsTestUtil.java b/src/test/java/org/folio/util/HoldingsTestUtil.java index 7a4f695ad..76a8a460a 100644 --- a/src/test/java/org/folio/util/HoldingsTestUtil.java +++ b/src/test/java/org/folio/util/HoldingsTestUtil.java @@ -12,21 +12,21 @@ import static org.folio.repository.holdings.HoldingsTableConstants.TITLE_ID_COLUMN; import static org.folio.repository.holdings.HoldingsTableConstants.VENDOR_ID_COLUMN; import static org.folio.repository.holdings.HoldingsTableConstants.insertOrUpdateHoldings; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.readJsonFile; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.readJsonFile; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Tuple; -import java.io.IOException; -import java.net.URISyntaxException; import java.time.OffsetDateTime; import java.util.List; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.repository.SqlQueryHelper; import org.folio.repository.holdings.DbHoldingInfo; import org.folio.rest.persist.PostgresClient; +@UtilityClass public class HoldingsTestUtil { public static List<DbHoldingInfo> getHoldings(Vertx vertx) { @@ -45,6 +45,12 @@ public static void saveHolding(String credentialsId, DbHoldingInfo holding, Offs future.join(); } + public static void saveHoldingsFromFiles(String credentialsId, Vertx vertx, String... filePaths) { + for (String filePath : filePaths) { + saveHolding(credentialsId, readJsonFile(filePath, DbHoldingInfo.class), OffsetDateTime.now(), vertx); + } + } + private static Tuple getHoldingsInsertParams(String credentialsId, DbHoldingInfo holding, OffsetDateTime updatedAt) { return Tuple.of( toUUID(credentialsId), @@ -59,10 +65,6 @@ private static Tuple getHoldingsInsertParams(String credentialsId, DbHoldingInfo ); } - public static DbHoldingInfo getStubHolding() throws IOException, URISyntaxException { - return readJsonFile("responses/kb-ebsco/holdings/custom-holding.json", DbHoldingInfo.class); - } - private static String holdingsTestTable() { return PostgresClient.convertToPsqlStandard(STUB_TENANT) + "." + HOLDINGS_TABLE; } diff --git a/src/test/java/org/folio/util/IntegrationTestBase.java b/src/test/java/org/folio/util/IntegrationTestBase.java new file mode 100644 index 000000000..7b3009334 --- /dev/null +++ b/src/test/java/org/folio/util/IntegrationTestBase.java @@ -0,0 +1,256 @@ +package org.folio.util; + +import static io.restassured.RestAssured.given; +import static org.apache.hc.core5.http.ContentType.APPLICATION_JSON; +import static org.folio.HttpStatus.SC_BAD_REQUEST; +import static org.folio.HttpStatus.SC_CREATED; +import static org.folio.HttpStatus.SC_NO_CONTENT; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.KB_CREDENTIALS_TABLE_NAME; +import static org.folio.rest.util.RestConstants.JSON_API_TYPE; +import static org.folio.util.KbCredentialsTestUtil.STUB_USER_ID; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.clearDataFromTable; +import static org.hamcrest.Matchers.notNullValue; + +import io.restassured.RestAssured; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.filter.log.LogDetail; +import io.restassured.http.Header; +import io.restassured.http.Headers; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import io.vertx.core.Vertx; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.folio.HttpHeaders; +import org.folio.cache.VertxCache; +import org.folio.okapi.common.XOkapiHeaders; +import org.folio.spring.SpringContextUtil; +import org.folio.spring.config.TestConfig; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +/** + * Base test class for tests that use WireMock and a Vert.x HTTP server backed by an embedded Postgres instance. + * + * <p> + * Each subclass starts and stops its own Vert.x + Postgres via {@link TestSetUpHelper} in {@code @BeforeAll} / + * {@code @AfterAll}. If a subclass needs its own {@code @BeforeAll} or {@code @AfterAll}, it must use a different + * method name to avoid hiding {@link #setUpClass()} / {@link #tearDownClass()}, or call them explicitly. + */ +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = TestConfig.class) +public abstract class IntegrationTestBase extends WireMockTestBase { + + protected static final Header CONTENT_TYPE_HEADER = new Header(HttpHeaders.CONTENT_TYPE, JSON_API_TYPE); + protected static final Header JSON_CONTENT_TYPE_HEADER = new Header(HttpHeaders.CONTENT_TYPE, + APPLICATION_JSON.getMimeType()); + + protected static String moduleUrl; + protected static Vertx vertx; + + @Autowired + private List<VertxCache<?, ?>> caches; + + @BeforeAll + public static void setUpClass() { + var configProperties = Map.of("spring.configuration", "org.folio.spring.config.TestConfig"); + TestSetUpHelper.startVertxAndPostgres(configProperties); + vertx = TestSetUpHelper.getVertx(); + moduleUrl = TestSetUpHelper.getModuleUrl(); + + // An ad-hoc to clear any records after DB setup but before test execution + // this should be removed once a proper separation between migration scripts and clean DB is in place + clearDataFromTable(vertx, KB_CREDENTIALS_TABLE_NAME); + } + + @AfterAll + public static void tearDownClass() { + TestSetUpHelper.stopVertxAndPostgres(); + } + + protected static String withInclude(String path, String... includes) { + var separator = path.contains("?") ? "&" : "?"; + return path + separator + "include=" + String.join(",", includes); + } + + protected static String withTagFilters(String path, String... tags) { + var separator = path.contains("?") ? "&" : "?"; + return path + Arrays.stream(tags) + .map(tag -> "filter[tags]=" + tag) + .collect(Collectors.joining("&", separator, "")); + } + + protected static String withAccessTypeFilters(String path, String... accessTypes) { + var separator = path.contains("?") ? "&" : "?"; + return path + Arrays.stream(accessTypes) + .map(type -> "filter[access-type]=" + type) + .collect(Collectors.joining("&", separator, "")); + } + + protected RequestSpecification getRequestSpecification() { + return new RequestSpecBuilder() + .addHeader(XOkapiHeaders.TENANT, STUB_TENANT) + .addHeader(XOkapiHeaders.USER_ID, STUB_USER_ID) + .addHeader(XOkapiHeaders.URL, getWiremockUrl()) + .setBaseUri(moduleUrl) + .log(LogDetail.ALL) + .build(); + } + + protected RequestSpecification givenWithUrl() { + return new RequestSpecBuilder() + .addHeader(XOkapiHeaders.URL, getWiremockUrl()) + .setBaseUri(moduleUrl) + .log(LogDetail.ALL) + .build(); + } + + protected void checkResponseNotEmptyWhenStatusIs400(String path) { + RestAssured.given() + .spec(getRequestSpecification()) + .when() + .get(path) + .then() + .statusCode(SC_BAD_REQUEST) + .body("errors.first.title", notNullValue()); + } + + protected ExtractableResponse<Response> getWithOk(String resourcePath) { + return getWithStatus(resourcePath, SC_OK); + } + + protected ExtractableResponse<Response> getWithOk(String endpoint, Header... headers) { + return getWithStatus(endpoint, SC_OK, headers); + } + + protected ExtractableResponse<Response> getWithStatus(String resourcePath, int expectedStatus) { + return given() + .spec(getRequestSpecification()) + .when() + .get(resourcePath) + .then() + .log() + .ifValidationFails() + .statusCode(expectedStatus) + .extract(); + } + + protected ExtractableResponse<Response> getWithStatus(String endpoint, int expectedStatus, Header... headers) { + return given() + .spec(getRequestSpecification()) + .headers(new Headers(headers)) + .when() + .get(endpoint) + .then() + .log() + .ifValidationFails() + .statusCode(expectedStatus) + .extract(); + } + + protected ExtractableResponse<Response> postWithOk(String endpoint, String postBody) { + return postWithStatus(endpoint, postBody, SC_OK, CONTENT_TYPE_HEADER); + } + + protected ExtractableResponse<Response> postWithCreated(String endpoint, String postBody) { + return postWithStatus(endpoint, postBody, SC_CREATED, CONTENT_TYPE_HEADER); + } + + protected ExtractableResponse<Response> postWithStatus(String resourcePath, String postBody, + int expectedStatus, Header... headers) { + return given() + .spec(getRequestSpecification()) + .header(JSON_CONTENT_TYPE_HEADER) + .header(CONTENT_TYPE_HEADER) + .headers(new Headers(headers)) + .body(postBody) + .when() + .post(resourcePath) + .then() + .log().ifValidationFails() + .statusCode(expectedStatus) + .extract(); + } + + protected ExtractableResponse<Response> putWithOk(String endpoint, String putBody) { + return putWithStatus(endpoint, putBody, SC_OK, CONTENT_TYPE_HEADER); + } + + protected ExtractableResponse<Response> putWithNoContent(String resourcePath, String putBody, Header... headers) { + return putWithStatus(resourcePath, putBody, SC_NO_CONTENT, headers); + } + + protected ExtractableResponse<Response> putWithStatus(String resourcePath, String putBody, + int expectedStatus, Header... headers) { + return given() + .spec(getRequestSpecification()) + .header(JSON_CONTENT_TYPE_HEADER) + .header(CONTENT_TYPE_HEADER) + .headers(new Headers(headers)) + .body(putBody) + .when() + .put(resourcePath) + .then() + .log().ifValidationFails() + .statusCode(expectedStatus) + .extract(); + } + + protected ExtractableResponse<Response> patchWithNoContent(String resourcePath, String patchBody) { + return patchWithStatus(resourcePath, patchBody, SC_NO_CONTENT); + } + + protected ExtractableResponse<Response> patchWithStatus(String resourcePath, String patchBody, int expectedStatus, + Header... headers) { + return given() + .spec(getRequestSpecification()) + .header(JSON_CONTENT_TYPE_HEADER) + .header(CONTENT_TYPE_HEADER) + .headers(new Headers(addContentHeader(headers))) + .body(patchBody) + .when() + .patch(resourcePath) + .then() + .log().ifValidationFails() + .statusCode(expectedStatus) + .extract(); + } + + protected ExtractableResponse<Response> deleteWithNoContent(String resourcePath) { + return deleteWithStatus(resourcePath, SC_NO_CONTENT); + } + + protected ExtractableResponse<Response> deleteWithStatus(String resourcePath, int expectedStatus) { + return given() + .spec(getRequestSpecification()) + .when() + .delete(resourcePath) + .then() + .log().ifValidationFails() + .statusCode(expectedStatus) + .extract(); + } + + @BeforeEach + void invalidateCache() { + SpringContextUtil.autowireDependenciesFromFirstContext(this, vertx); + caches.forEach(VertxCache::invalidateAll); + } + + private Header[] addContentHeader(Header[] headers) { + List<Header> headerList = new ArrayList<>(Arrays.asList(headers)); + headerList.add(CONTENT_TYPE_HEADER); + return headerList.toArray(new Header[0]); + } +} diff --git a/src/test/java/org/folio/util/KbCredentialsTestUtil.java b/src/test/java/org/folio/util/KbCredentialsTestUtil.java index ad34b9a21..6ab3b6747 100644 --- a/src/test/java/org/folio/util/KbCredentialsTestUtil.java +++ b/src/test/java/org/folio/util/KbCredentialsTestUtil.java @@ -18,7 +18,7 @@ import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.URL_COLUMN; import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.selectCredentialsQuery; import static org.folio.repository.kbcredentials.KbCredentialsTableConstants.upsertCredentialsQuery; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.restassured.http.Header; import io.vertx.core.Vertx; @@ -32,44 +32,48 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.okapi.common.XOkapiHeaders; import org.folio.repository.kbcredentials.DbKbCredentials; import org.folio.rest.converter.kbcredentials.KbCredentialsConverter; import org.folio.rest.jaxrs.model.KbCredentials; +import org.folio.rest.jaxrs.model.KbCredentialsDataAttributes; +import org.folio.rest.jaxrs.model.KbCredentialsPatchRequest; +import org.folio.rest.jaxrs.model.KbCredentialsPatchRequestData; +import org.folio.rest.jaxrs.model.KbCredentialsPatchRequestDataAttributes; import org.folio.rest.persist.PostgresClient; import org.springframework.core.convert.converter.Converter; +@UtilityClass public class KbCredentialsTestUtil { public static final String KB_CREDENTIALS_ENDPOINT = "/eholdings/kb-credentials"; public static final String USER_KB_CREDENTIAL_ENDPOINT = "/eholdings/user-kb-credential"; public static final String KB_CREDENTIALS_CUSTOM_LABELS_ENDPOINT = KB_CREDENTIALS_ENDPOINT + "/%s/custom-labels"; - public static final String STUB_CREDENTIALS_NAME = "TEST_NAME"; - public static final String STUB_API_KEY = "TEST_API_KEY"; - public static final String STUB_API_URL = "https://api.ebsco.io"; - public static final String STUB_CUSTOMER_ID = "TEST_CUSTOMER_ID"; + public static final String CREDENTIALS_NAME = "TEST_NAME"; + public static final String API_KEY = "TEST_API_KEY"; + public static final String API_URL = "https://api.ebsco.io"; + public static final String CUSTOMER_ID = "TEST_CUSTOMER_ID"; public static final String STUB_USERNAME = "TEST_USER_NAME"; - public static final String STUB_USERNAME_OTHER = "TEST_USER_NAME_OTHER"; public static final String STUB_USER_ID = "88888888-8888-4888-8888-888888888888"; public static final String STUB_USER_OTHER_ID = "99999999-9999-4999-9999-999999999999"; - public static final Header STUB_USER_ID_HEADER = new Header(XOkapiHeaders.USER_ID, STUB_USER_ID); public static final Header STUB_USER_ID_OTHER_HEADER = new Header(XOkapiHeaders.USER_ID, STUB_USER_OTHER_ID); private static final Converter<DbKbCredentials, KbCredentials> CONVERTER = - new KbCredentialsConverter.KbCredentialsFromDbSecuredConverter(STUB_API_KEY); + new KbCredentialsConverter.KbCredentialsFromDbSecuredConverter(API_KEY); private static final Converter<DbKbCredentials, KbCredentials> CONVERTER_NON_SECURED = - new KbCredentialsConverter.KbCredentialsFromDbNonSecuredConverter(STUB_API_KEY); + new KbCredentialsConverter.KbCredentialsFromDbNonSecuredConverter(API_KEY); public static String saveKbCredentials(String url, String name, String apiKey, String customerId, Vertx vertx) { return saveKbCredentials(UUID.randomUUID().toString(), url, name, apiKey, customerId, vertx); } public static String saveKbCredentials(String id, String url, Vertx vertx) { - return saveKbCredentials(id, url, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + return saveKbCredentials(id, url, CREDENTIALS_NAME, API_KEY, CUSTOMER_ID, vertx); } public static String saveKbCredentials(String id, String url, String name, String apiKey, String customerId, @@ -93,6 +97,63 @@ public static String saveKbCredentials(String id, String url, String name, Strin return id; } + public static String setupDefaultKbConfiguration(String wiremockUrl, Vertx vertx) { + return saveKbCredentials(wiremockUrl, CREDENTIALS_NAME, API_KEY, CUSTOMER_ID, vertx); + } + + public static KbCredentials getDefaultKbConfiguration(Vertx vertx) { + List<KbCredentials> credentials = getKbCredentialsNonSecured(vertx); + if (credentials.size() != 1) { + throw new UnsupportedOperationException("There is 0 or more then 1 configuration"); + } else { + return credentials.getFirst(); + } + } + + public static List<KbCredentials> getKbCredentialsNonSecured(Vertx vertx) { + return getKbCredentials(vertx, CONVERTER_NON_SECURED); + } + + public static KbCredentials stubbedCredentials(String url) { + return new KbCredentials() + .withType(KbCredentials.Type.KB_CREDENTIALS) + .withAttributes(new KbCredentialsDataAttributes() + .withName(CREDENTIALS_NAME) + .withCustomerId(CUSTOMER_ID) + .withApiKey(API_KEY) + .withUrl(url)); + } + + public static KbCredentialsPatchRequest stubPatchRequest() { + return new KbCredentialsPatchRequest().withData( + new KbCredentialsPatchRequestData().withType(KbCredentialsPatchRequestData.Type.KB_CREDENTIALS) + .withAttributes(new KbCredentialsPatchRequestDataAttributes()) + ); + } + + public static DbKbCredentials getCredentialsNoUrl() { + return DbKbCredentials.builder() + .name(CREDENTIALS_NAME) + .customerId(CUSTOMER_ID) + .apiKey(API_KEY).build(); + } + + public static DbKbCredentials getCredentials() { + return DbKbCredentials.builder() + .name(CREDENTIALS_NAME) + .customerId(CUSTOMER_ID) + .apiKey(API_KEY) + .url(API_URL).build(); + } + + public static Collection<DbKbCredentials> getCredentialsCollectionNoUrl() { + return Collections.singletonList(getCredentialsNoUrl()); + } + + public static Collection<DbKbCredentials> getCredentialsCollection() { + return Collections.singletonList(getCredentials()); + } + public static List<KbCredentials> getKbCredentials(Vertx vertx) { return getKbCredentials(vertx, CONVERTER); } @@ -106,10 +167,6 @@ private static List<KbCredentials> getKbCredentials(Vertx vertx, return future.join(); } - public static List<KbCredentials> getKbCredentialsNonSecured(Vertx vertx) { - return getKbCredentials(vertx, CONVERTER_NON_SECURED); - } - private static DbKbCredentials mapKbCredentials(Row row) { return DbKbCredentials.builder() .id(row.getUUID(ID_COLUMN)) @@ -129,27 +186,4 @@ private static DbKbCredentials mapKbCredentials(Row row) { private static String kbCredentialsTestTable() { return PostgresClient.convertToPsqlStandard(STUB_TENANT) + "." + KB_CREDENTIALS_TABLE_NAME; } - - public static DbKbCredentials getCredentialsNoUrl() { - return DbKbCredentials.builder() - .name(STUB_CREDENTIALS_NAME) - .customerId(STUB_CUSTOMER_ID) - .apiKey(STUB_API_KEY).build(); - } - - public static DbKbCredentials getCredentials() { - return DbKbCredentials.builder() - .name(STUB_CREDENTIALS_NAME) - .customerId(STUB_CUSTOMER_ID) - .apiKey(STUB_API_KEY) - .url(STUB_API_URL).build(); - } - - public static Collection<DbKbCredentials> getCredentialsCollectionNoUrl() { - return Collections.singletonList(getCredentialsNoUrl()); - } - - public static Collection<DbKbCredentials> getCredentialsCollection() { - return Collections.singletonList(getCredentials()); - } } diff --git a/src/test/java/org/folio/util/PackagesTestUtil.java b/src/test/java/org/folio/util/PackagesTestUtil.java index e57ee674c..b0b5cd6d0 100644 --- a/src/test/java/org/folio/util/PackagesTestUtil.java +++ b/src/test/java/org/folio/util/PackagesTestUtil.java @@ -10,42 +10,26 @@ import static org.folio.repository.packages.PackageTableConstants.ID_COLUMN; import static org.folio.repository.packages.PackageTableConstants.NAME_COLUMN; import static org.folio.repository.packages.PackageTableConstants.PACKAGES_TABLE_NAME; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_CONTENT_TYPE; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID_2; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_ID_3; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME_2; -import static org.folio.rest.impl.PackagesTestData.STUB_PACKAGE_NAME_3; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID_2; -import static org.folio.rest.impl.ProvidersTestData.STUB_VENDOR_ID_3; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.mockGetWithBody; -import static org.folio.test.util.TestUtil.readJsonFile; +import static org.folio.util.RmApiConstants.STUB_PACKAGE_CONTENT_TYPE; +import static org.folio.util.TestUtil.STUB_TENANT; -import com.github.tomakehurst.wiremock.matching.RegexPattern; import io.vertx.core.Vertx; -import io.vertx.core.json.Json; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Tuple; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.folio.holdingsiq.model.PackageByIdData; +import lombok.experimental.UtilityClass; import org.folio.repository.packages.DbPackage; +import org.folio.rest.jaxrs.model.PackagePutData; +import org.folio.rest.jaxrs.model.PackagePutDataAttributes; +import org.folio.rest.jaxrs.model.PackagePutRequest; import org.folio.rest.persist.PostgresClient; import org.folio.rest.util.IdParser; +@UtilityClass public final class PackagesTestUtil { - private static final String STUB_PACKAGE_JSON_PATH = "responses/rmapi/packages/get-package-by-id-response.json"; - - private PackagesTestUtil() { - } - public static List<DbPackage> getPackages(Vertx vertx) { CompletableFuture<List<DbPackage>> future = new CompletableFuture<>(); String query = prepareQuery(selectQuery(), packageTestTable()); @@ -70,40 +54,11 @@ public static void savePackage(DbPackage dbPackage, Vertx vertx) { future.join(); } - public static String getPackageResponse(String packageName, String packageId, String providerId) - throws IOException, URISyntaxException { - PackageByIdData packageData = readJsonFile(STUB_PACKAGE_JSON_PATH, PackageByIdData.class); - return Json.encode(packageData.toByIdBuilder() - .packageName(packageName) - .packageId(Integer.parseInt(packageId)) - .vendorId(Integer.parseInt(providerId)) - .build()); - } - - public static void setUpPackages(Vertx vertx, String credentialsId) throws IOException, URISyntaxException { - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID, STUB_VENDOR_ID, STUB_PACKAGE_NAME); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_2, STUB_VENDOR_ID_2, STUB_PACKAGE_NAME_2); - setUpPackage(vertx, credentialsId, STUB_PACKAGE_ID_3, STUB_VENDOR_ID_3, STUB_PACKAGE_NAME_3); - } - - public static void setUpPackage(Vertx vertx, String credentialsId, String packageId, String vendorId, - String packageName) - throws IOException, URISyntaxException { - savePackage(buildDbPackage(vendorId + "-" + packageId, credentialsId, packageName), vertx); - mockPackageWithName(packageId, vendorId, packageName); - } - - public static void mockPackageWithName(String stubPackageId, String stubProviderId, String stubPackageName) - throws IOException, URISyntaxException { - mockGetWithBody(new RegexPattern(".*vendors/" + stubProviderId + "/packages/" + stubPackageId), - getPackageResponse(stubPackageName, stubPackageId, stubProviderId)); - } - public static DbPackage buildDbPackage(String id, String credentialsId, String name) { return buildDbPackage(id, toUUID(credentialsId), name, STUB_PACKAGE_CONTENT_TYPE); } - private static DbPackage buildDbPackage(String id, UUID credentialsId, String name, String contentType) { + public static DbPackage buildDbPackage(String id, UUID credentialsId, String name, String contentType) { return DbPackage.builder() .id(IdParser.parsePackageId(id)) .credentialsId(credentialsId) @@ -112,6 +67,13 @@ private static DbPackage buildDbPackage(String id, UUID credentialsId, String na .build(); } + public static PackagePutRequest getPackagePutRequest(PackagePutDataAttributes attributes) { + return new PackagePutRequest() + .withData(new PackagePutData() + .withType(PackagePutData.Type.PACKAGES) + .withAttributes(attributes)); + } + private static DbPackage mapDbPackage(Row row) { return buildDbPackage( row.getString(ID_COLUMN), diff --git a/src/test/java/org/folio/util/ProvidersTestUtil.java b/src/test/java/org/folio/util/ProvidersTestUtil.java index 3198462e3..88cf029d4 100644 --- a/src/test/java/org/folio/util/ProvidersTestUtil.java +++ b/src/test/java/org/folio/util/ProvidersTestUtil.java @@ -9,7 +9,7 @@ import static org.folio.repository.providers.ProviderTableConstants.ID_COLUMN; import static org.folio.repository.providers.ProviderTableConstants.NAME_COLUMN; import static org.folio.repository.providers.ProviderTableConstants.PROVIDERS_TABLE_NAME; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; @@ -17,15 +17,13 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.repository.providers.DbProvider; import org.folio.rest.persist.PostgresClient; +@UtilityClass public final class ProvidersTestUtil { - private ProvidersTestUtil() { - throw new UnsupportedOperationException("Do not instantiate"); - } - public static List<DbProvider> getProviders(Vertx vertx) { CompletableFuture<List<DbProvider>> future = new CompletableFuture<>(); String query = prepareQuery(selectQuery(), providerTestTable()); @@ -42,20 +40,21 @@ public static void saveProvider(DbProvider provider, Vertx vertx) { future.join(); } - public static DbProvider buildDbProvider(String id, String credentialsId, String name) { + public static DbProvider buildDbProvider(int id, String credentialsId, String name) { return buildDbProvider(id, toUUID(credentialsId), name); } - private static DbProvider buildDbProvider(String id, UUID credentialsId, String name) { + private static DbProvider buildDbProvider(int id, UUID credentialsId, String name) { return DbProvider.builder() - .id(id) + .id(String.valueOf(id)) .credentialsId(credentialsId) .name(name) .build(); } private static DbProvider mapDbProvider(Row row) { - return buildDbProvider(row.getString(ID_COLUMN), row.getUUID(CREDENTIALS_ID_COLUMN), row.getString(NAME_COLUMN)); + return buildDbProvider(Integer.parseInt(row.getString(ID_COLUMN)), row.getUUID(CREDENTIALS_ID_COLUMN), + row.getString(NAME_COLUMN)); } private static String providerTestTable() { diff --git a/src/test/java/org/folio/util/ResourcesTestUtil.java b/src/test/java/org/folio/util/ResourcesTestUtil.java index 2930ff4d5..9823bdfc8 100644 --- a/src/test/java/org/folio/util/ResourcesTestUtil.java +++ b/src/test/java/org/folio/util/ResourcesTestUtil.java @@ -10,7 +10,7 @@ import static org.folio.repository.resources.ResourceTableConstants.NAME_COLUMN; import static org.folio.repository.resources.ResourceTableConstants.RESOURCES_TABLE_NAME; import static org.folio.rest.util.IdParser.resourceIdToString; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; @@ -18,16 +18,17 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.repository.resources.DbResource; +import org.folio.rest.jaxrs.model.ResourcePutData; +import org.folio.rest.jaxrs.model.ResourcePutDataAttributes; +import org.folio.rest.jaxrs.model.ResourcePutRequest; import org.folio.rest.persist.PostgresClient; import org.folio.rest.util.IdParser; +@UtilityClass public final class ResourcesTestUtil { - private ResourcesTestUtil() { - throw new UnsupportedOperationException("Cannot instantiate utility class."); - } - public static List<DbResource> getResources(Vertx vertx) { CompletableFuture<List<DbResource>> future = new CompletableFuture<>(); String query = prepareQuery(selectQuery(), resourceTestTable()); @@ -49,10 +50,17 @@ public static DbResource buildResource(String id, String credentialsId, String n return buildResource(id, toUUID(credentialsId), name); } - private static DbResource buildResource(String id, UUID credentialsId, String name) { + public static DbResource buildResource(String id, UUID credentialsId, String name) { return DbResource.builder().id(IdParser.parseResourceId(id)).credentialsId(credentialsId).name(name).build(); } + public static ResourcePutRequest getResourcePutRequest(ResourcePutDataAttributes attributes) { + return new ResourcePutRequest() + .withData(new ResourcePutData() + .withType(ResourcePutData.Type.RESOURCES) + .withAttributes(attributes)); + } + private static DbResource mapDbResource(Row row) { return buildResource(row.getString(ID_COLUMN), row.getUUID(CREDENTIALS_ID_COLUMN), row.getString(NAME_COLUMN)); } diff --git a/src/test/java/org/folio/util/RmApiConstants.java b/src/test/java/org/folio/util/RmApiConstants.java new file mode 100644 index 000000000..1f31901ed --- /dev/null +++ b/src/test/java/org/folio/util/RmApiConstants.java @@ -0,0 +1,160 @@ +package org.folio.util; + +public abstract class RmApiConstants { + + // Credentials + protected static final String STUB_API_KEY = "TEST_API_KEY"; + protected static final String STUB_CREDENTIALS_ID = "12312312-1231-1231-a111-111111111111"; + protected static final String STUB_CUSTOMER_ID = "TEST_CUSTOMER_ID"; + + // Vendor/Provider IDs and names + protected static final int STUB_VENDOR_ID = 19; + protected static final int STUB_VENDOR_ID_2 = 153; + protected static final int STUB_VENDOR_ID_3 = 167; + protected static final int CUSTOM_VENDOR_ID = 123356; + protected static final String STUB_VENDOR_NAME = "Vendor Name1"; + protected static final String STUB_VENDOR_NAME_2 = "Vendor Name2"; + protected static final String STUB_VENDOR_NAME_3 = "Vendor Name3"; + + // Package IDs and names + protected static final int STUB_PACKAGE_ID = 3964; + protected static final int STUB_PACKAGE_ID_2 = 13964; + protected static final int STUB_PACKAGE_ID_3 = 23964; + protected static final int CUSTOM_PACKAGE_ID = 3157070; + protected static final String STUB_PACKAGE_NAME = "EBSCO Biotechnology Collection: India"; + protected static final String STUB_PACKAGE_NAME_2 = "package 2"; + protected static final String STUB_PACKAGE_NAME_3 = "package 3"; + protected static final String STUB_PACKAGE_CONTENT_TYPE = "AggregatedFullText"; + + // Title IDs and names + protected static final int STUB_TITLE_ID = 985846; + protected static final int STUB_MANAGED_TITLE_ID = 762169; + protected static final int STUB_MANAGED_TITLE_ID_2 = 1108525; + protected static final int CUSTOM_TITLE_ID = 19412030; + protected static final String STUB_TITLE_NAME = "F. Scott Fitzgerald's The Great Gatsby (Great Gatsby)"; + protected static final String STUB_CUSTOM_TITLE_NAME = "Test Title"; + + // Compound resource IDs + protected static final String STUB_CUSTOM_RESOURCE_ID = + CUSTOM_VENDOR_ID + "-" + CUSTOM_PACKAGE_ID + "-" + CUSTOM_TITLE_ID; + protected static final String STUB_MANAGED_RESOURCE_ID = + STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID + "-" + STUB_MANAGED_TITLE_ID; + protected static final String STUB_MANAGED_RESOURCE_ID_2 = + STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID + "-" + STUB_MANAGED_TITLE_ID_2; + protected static final String STUB_MANAGED_RESOURCE_ID_3 = + STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID_2 + "-" + STUB_MANAGED_TITLE_ID_2; + + // Compound package IDs + protected static final String FULL_PACKAGE_ID = STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID; + protected static final String FULL_PACKAGE_ID_2 = STUB_VENDOR_ID_2 + "-" + STUB_PACKAGE_ID_2; + protected static final String FULL_PACKAGE_ID_3 = STUB_VENDOR_ID_3 + "-" + STUB_PACKAGE_ID_3; + protected static final String FULL_PACKAGE_ID_4 = STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID_2; + protected static final String FULL_PACKAGE_ID_5 = STUB_VENDOR_ID + "-" + STUB_PACKAGE_ID_3; + + // Tags + protected static final String STUB_TAG_VALUE = "tag one"; + protected static final String STUB_TAG_VALUE_2 = "tag 2"; + protected static final String STUB_TAG_VALUE_3 = "tag 3"; + protected static final String STUB_TAG_VALUE_4 = "tag 4"; + + // API URL constants + protected static final String RM_ACCOUNTS_BASE_URL = "/rm/rmaccounts/"; + protected static final String RM_ACCOUNTS_V2_BASE_URL = "/rm/rmaccounts/v2/"; + protected static final String RM_ACCOUNT_API_PATH = RM_ACCOUNTS_BASE_URL + STUB_CUSTOMER_ID; + protected static final String RM_ACCOUNT_V2_API_PATH = RM_ACCOUNTS_V2_BASE_URL + STUB_CUSTOMER_ID; + protected static final String RM_ACCOUNTS_ANY_PATH_REGEX = "/rm/rmaccounts.*"; + + protected String providerTagsPath() { + return "eholdings/providers/" + STUB_VENDOR_ID + "/tags"; + } + + protected String proxiesRmApi() { + return RM_ACCOUNT_API_PATH + "/proxies.*"; + } + + protected String holdingsStatusRmApi() { + return RM_ACCOUNT_API_PATH + "/holdings/status"; + } + + protected String postHoldingsRmApi() { + return RM_ACCOUNT_API_PATH + "/holdings"; + } + + protected String postTransactionsHoldingsRmApi() { + return RM_ACCOUNT_API_PATH + "/reports/holdings"; + } + + protected String transactionsRmApi() { + return RM_ACCOUNT_API_PATH + "/reports/holdings/transactions"; + } + + protected String deltasRmApi() { + return RM_ACCOUNT_API_PATH + "/reports/holdings/deltas"; + } + + protected String rootProxyCustomLabelsRmApi() { + return RM_ACCOUNT_API_PATH + "/"; + } + + protected String transactionByIdRmApi(String transactionId) { + return RM_ACCOUNT_API_PATH + "/reports/holdings/transactions/" + transactionId; + } + + protected String transactionStatusRmApi(String transactionId) { + return RM_ACCOUNT_API_PATH + "/reports/holdings/transactions/" + transactionId + "/status"; + } + + protected String deltaByIdRmApi(String deltaId) { + return RM_ACCOUNT_API_PATH + "/reports/holdings/deltas/" + deltaId; + } + + protected String deltaStatusRmApi(String deltaId) { + return RM_ACCOUNT_API_PATH + "/reports/holdings/deltas/" + deltaId + "/status"; + } + + protected String resourcesRmApi(int vendorId, int packageId, int titleId) { + return RM_ACCOUNT_API_PATH + "/vendors/" + vendorId + "/packages/" + packageId + "/titles/" + titleId; + } + + protected String packageTitlesRmApi(int vendorId, int packageId) { + return RM_ACCOUNT_API_PATH + "/vendors/" + vendorId + "/packages/" + packageId + "/titles"; + } + + protected String packagesRmApi() { + return RM_ACCOUNT_V2_API_PATH + "/lists"; + } + + protected String packageRmApi(int packageId) { + return RM_ACCOUNT_V2_API_PATH + "/lists/" + packageId; + } + + protected String packageRmApiV1(int vendorId) { + return RM_ACCOUNT_API_PATH + "/vendors/" + vendorId + "/packages"; + } + + protected String providerPackagesRmApi(int vendorId) { + return RM_ACCOUNT_V2_API_PATH + "/vendors/" + vendorId + "/lists"; + } + + protected String titlesRmApi() { + return RM_ACCOUNT_API_PATH + "/titles"; + } + + protected String titlesRmApi(int titleId) { + return RM_ACCOUNT_API_PATH + "/titles/" + titleId; + } + + protected String vendorsRmApi() { + return RM_ACCOUNT_API_PATH + "/vendors"; + } + + protected static String vendorsRmApi(int vendorId) { + return RM_ACCOUNT_API_PATH + "/vendors/" + vendorId; + } + + protected String ucCostPerUseTitlesUrl(String year, String month, String currency, + boolean publisherPlatform, boolean previousYear) { + return "/uc/costperuse/titles?fiscalYear=%s&fiscalMonth=%s&analysisCurrency=%s&publisherPlatform=%s&previousYear=%s" + .formatted(year, month, currency, publisherPlatform, previousYear); + } +} diff --git a/src/test/java/org/folio/util/TagsTestUtil.java b/src/test/java/org/folio/util/TagsTestUtil.java index 655a69188..59a06a3c5 100644 --- a/src/test/java/org/folio/util/TagsTestUtil.java +++ b/src/test/java/org/folio/util/TagsTestUtil.java @@ -9,7 +9,7 @@ import static org.folio.repository.tag.TagTableConstants.RECORD_TYPE_COLUMN; import static org.folio.repository.tag.TagTableConstants.TAGS_TABLE_NAME; import static org.folio.repository.tag.TagTableConstants.TAG_COLUMN; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; @@ -20,14 +20,29 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.db.RowSetUtils; import org.folio.repository.RecordType; import org.folio.repository.tag.DbTag; import org.folio.rest.persist.PostgresClient; +@UtilityClass public final class TagsTestUtil { - private TagsTestUtil() { + public static DbTag buildTag(int recordId, RecordType recordType, String value) { + return buildTag(String.valueOf(recordId), recordType, value); + } + + public static DbTag buildTag(String recordId, RecordType recordType, String value) { + return DbTag.builder() + .recordId(recordId) + .recordType(recordType) + .value(value) + .build(); + } + + public static void saveTag(Vertx vertx, int recordId, RecordType recordType, String value) { + saveTag(vertx, String.valueOf(recordId), recordType, value); } public static void saveTag(Vertx vertx, String recordId, RecordType recordType, String value) { @@ -58,17 +73,6 @@ public static List<DbTag> saveTags(List<DbTag> tags, Vertx vertx) { return populateTagIds(tags, future.join()); } - private static List<DbTag> populateTagIds(List<DbTag> tags, RowSet<Row> keys) { - List<DbTag> result = new ArrayList<>(tags.size()); - - RowIterator<Row> iterator = keys.iterator(); - for (DbTag tag : tags) { - result.add(tag.toBuilder().id(iterator.next().getUUID(ID_COLUMN)).build()); - } - - return result; - } - public static List<String> getTags(Vertx vertx) { CompletableFuture<List<String>> future = new CompletableFuture<>(); String query = prepareQuery(selectQuery(TAG_COLUMN), tagTestTable()); @@ -87,6 +91,17 @@ public static List<String> getTagsForRecordType(Vertx vertx, RecordType recordTy return future.join(); } + private static List<DbTag> populateTagIds(List<DbTag> tags, RowSet<Row> keys) { + List<DbTag> result = new ArrayList<>(tags.size()); + + RowIterator<Row> iterator = keys.iterator(); + for (DbTag tag : tags) { + result.add(tag.toBuilder().id(iterator.next().getUUID(ID_COLUMN)).build()); + } + + return result; + } + private static String tagTestTable() { return PostgresClient.convertToPsqlStandard(STUB_TENANT) + "." + TAGS_TABLE_NAME; } diff --git a/src/test/java/org/folio/util/TestFutureFailedException.java b/src/test/java/org/folio/util/TestFutureFailedException.java new file mode 100644 index 000000000..b8204599a --- /dev/null +++ b/src/test/java/org/folio/util/TestFutureFailedException.java @@ -0,0 +1,13 @@ +package org.folio.util; + +/** + * Exception to indicate that a future operation has failed during test execution. + * This runtime exception is intended to be thrown when asynchronous operations + * represented by futures do not complete successfully. + */ +public class TestFutureFailedException extends RuntimeException { + + public TestFutureFailedException(Throwable cause) { + super(cause); + } +} diff --git a/src/test/java/org/folio/util/TestSetUpHelper.java b/src/test/java/org/folio/util/TestSetUpHelper.java new file mode 100644 index 000000000..5b46b8969 --- /dev/null +++ b/src/test/java/org/folio/util/TestSetUpHelper.java @@ -0,0 +1,100 @@ +package org.folio.util; + +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TOKEN; + +import io.vertx.core.AsyncResult; +import io.vertx.core.DeploymentOptions; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.client.HttpResponse; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.folio.postgres.testing.PostgresTesterContainer; +import org.folio.rest.RestVerticle; +import org.folio.rest.client.TenantClient; +import org.folio.rest.jaxrs.model.TenantAttributes; +import org.folio.rest.jaxrs.model.TenantJob; +import org.folio.rest.persist.PostgresClient; +import org.folio.rest.tools.utils.NetworkUtils; + +public class TestSetUpHelper { + + private static final String HTTP_PORT = "http.port"; + private static final String MODULE_TO_VERSION = "mod-1.0.0"; + private static final int TENANT_OP_WAITING_TIME = 60000; + + private static int port; + private static String host; + private static Vertx vertx; + + public static void startVertxAndPostgres(Map<String, String> configProperties) { + port = NetworkUtils.nextFreePort(); + host = "http://127.0.0.1"; + vertx = Vertx.vertx(); + startPostgresContainer(); + + var future = new CompletableFuture<>(); + vertx.deployVerticle(RestVerticle.class.getName(), getDeploymentOptions(configProperties)) + .onComplete(event -> { + var tenantClient = new TenantClient(getModuleUrl(), STUB_TENANT, STUB_TOKEN, vertx.createHttpClient()); + try { + var tenantAttributes = new TenantAttributes().withModuleTo(MODULE_TO_VERSION); + tenantClient.postTenant(tenantAttributes, res1 -> { + if (res1.succeeded()) { + checkTenantOpStatus(res1, tenantClient, future); + } else { + future.completeExceptionally(new IllegalStateException("Failed to create tenant job")); + } + }); + } catch (Exception e) { + future.completeExceptionally(e); + } + }); + future.join(); + } + + public static void stopVertxAndPostgres() { + var future = new CompletableFuture<>(); + vertx.close().onComplete(res -> future.complete(null)); + future.join(); + } + + public static Vertx getVertx() { + return vertx; + } + + public static String getModuleUrl() { + return host + ":" + port; + } + + private static void checkTenantOpStatus(AsyncResult<HttpResponse<Buffer>> result, TenantClient tenantClient, + CompletableFuture<Object> future) { + var jobId = result.result().bodyAsJson(TenantJob.class).getId(); + tenantClient.getTenantByOperationId(jobId, TENANT_OP_WAITING_TIME, res2 -> { + if (res2.succeeded()) { + future.complete(null); + } else { + future.completeExceptionally(new IllegalStateException("Failed to get tenant")); + } + }); + } + + private static void startPostgresContainer() { + try { + PostgresClient.setPostgresTester(new PostgresTesterContainer()); + PostgresClient.getInstance(vertx).startPostgresTester(); + } catch (Exception e) { + throw new IllegalStateException("Failed to initialize postgres client", e); + } + } + + private static DeploymentOptions getDeploymentOptions(Map<String, String> configProperties) { + JsonObject config = new JsonObject() + .put(HTTP_PORT, port); + configProperties.forEach(config::put); + return new DeploymentOptions().setConfig(config + ); + } +} diff --git a/src/test/java/org/folio/util/TestStartLoggingExtension.java b/src/test/java/org/folio/util/TestStartLoggingExtension.java new file mode 100644 index 000000000..2f787e5a8 --- /dev/null +++ b/src/test/java/org/folio/util/TestStartLoggingExtension.java @@ -0,0 +1,22 @@ +package org.folio.util; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +public final class TestStartLoggingExtension implements BeforeTestExecutionCallback { + + private static final Logger LOG = LogManager.getLogger("Test"); + + private TestStartLoggingExtension() { } + + @Override + public void beforeTestExecution(ExtensionContext context) { + LOG.info( + "********** Running test method: {}.{} **********", + context.getRequiredTestClass().getName(), + context.getRequiredTestMethod().getName() + ); + } +} diff --git a/src/test/java/org/folio/util/KbTestUtil.java b/src/test/java/org/folio/util/TestUtil.java similarity index 54% rename from src/test/java/org/folio/util/KbTestUtil.java rename to src/test/java/org/folio/util/TestUtil.java index e28192ec4..06a8387f4 100644 --- a/src/test/java/org/folio/util/KbTestUtil.java +++ b/src/test/java/org/folio/util/TestUtil.java @@ -1,51 +1,69 @@ package org.folio.util; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.folio.repository.DbUtil.getTableName; import static org.folio.repository.DbUtil.prepareQuery; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.logger; -import static org.folio.util.KbCredentialsTestUtil.STUB_API_KEY; -import static org.folio.util.KbCredentialsTestUtil.STUB_CREDENTIALS_NAME; -import static org.folio.util.KbCredentialsTestUtil.STUB_CUSTOMER_ID; -import static org.folio.util.KbCredentialsTestUtil.getKbCredentialsNonSecured; +import com.fasterxml.jackson.databind.ObjectMapper; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.eventbus.DeliveryContext; import io.vertx.core.eventbus.Message; -import java.util.List; +import java.io.File; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; +import org.apache.commons.io.FileUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.folio.repository.SqlQueryHelper; -import org.folio.rest.jaxrs.model.KbCredentials; import org.folio.rest.persist.PostgresClient; import org.folio.service.holdings.message.LoadHoldingsMessage; -/** - * Contains common methods that are used in mod-kb-ebsco-java. - */ -public final class KbTestUtil { +@UtilityClass +public class TestUtil { - private KbTestUtil() { } + public static final String STUB_TENANT = "fs"; + public static final String STUB_TOKEN = "token"; + + private static final long TIMEOUT = 30; + private static final Logger LOG = LogManager.getLogger("KbTestUtil"); + + public static <T> T result(CompletableFuture<T> future) { + try { + return future.get(TIMEOUT, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new TestFutureFailedException(e.getCause() != null ? e.getCause() : e); + } + } /** - * Mocks wiremock server to return default test RM API configuration from database, - * RM API url will be changed to wiremockUrl so that following requests to RM API will be sent to wiremock instead. - * - * @param wiremockUrl wiremock url with port + * Reads file from classpath as String. */ - public static void setupDefaultKbConfiguration(String wiremockUrl, Vertx vertx) { - KbCredentialsTestUtil.saveKbCredentials(wiremockUrl, STUB_CREDENTIALS_NAME, STUB_API_KEY, STUB_CUSTOMER_ID, vertx); + @SneakyThrows + public static String readFile(String filename) { + return FileUtils.readFileToString(getFile(filename), UTF_8); } - public static KbCredentials getDefaultKbConfiguration(Vertx vertx) { - List<KbCredentials> credentials = getKbCredentialsNonSecured(vertx); - if (credentials.size() != 1) { - throw new UnsupportedOperationException("There is 0 or more then 1 configuration"); - } else { - return credentials.getFirst(); - } + /** + * Reads json file from classpath and parses it into object of specified class. + */ + @SneakyThrows + public static <T> T readJsonFile(String filename, Class<T> valueType) { + return new ObjectMapper().readValue(FileUtils.readFileToString(getFile(filename), UTF_8), valueType); + } + + /** + * Returns File object corresponding to the file on classpath with specified filename. + */ + @SneakyThrows + public static File getFile(String filename) { + return new File(TestUtil.class.getClassLoader().getResource(filename).toURI()); } public static void clearDataFromTable(Vertx vertx, String tableName) { @@ -54,7 +72,7 @@ public static void clearDataFromTable(Vertx vertx, String tableName) { PostgresClient.getInstance(vertx, STUB_TENANT) .execute(query, event -> { - logger().info("Table cleaned up: {}", tableName); + LOG.info("Table cleaned up: {}", tableName); future.complete(null); }); future.join(); @@ -84,12 +102,12 @@ public static Handler<DeliveryContext<LoadHoldingsMessage>> interceptAndStop(Str }; } - private static boolean messageMatches(String serviceAddress, String serviceMethodName, Message<?> message) { - return serviceAddress.equals(message.address()) - && serviceMethodName.equals(message.headers().get("action")); - } - public static String randomId() { return UUID.randomUUID().toString(); } + + private static boolean messageMatches(String serviceAddress, String serviceMethodName, Message<?> message) { + return serviceAddress.equals(message.address()) + && serviceMethodName.equals(message.headers().get("action")); + } } diff --git a/src/test/java/org/folio/util/TitlesTestUtil.java b/src/test/java/org/folio/util/TitlesTestUtil.java index 30e7c22e9..a50a7e4b8 100644 --- a/src/test/java/org/folio/util/TitlesTestUtil.java +++ b/src/test/java/org/folio/util/TitlesTestUtil.java @@ -1,7 +1,5 @@ package org.folio.util; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static org.folio.db.RowSetUtils.toUUID; import static org.folio.repository.DbUtil.prepareQuery; import static org.folio.repository.SqlQueryHelper.insertQuery; @@ -9,31 +7,23 @@ import static org.folio.repository.titles.TitlesTableConstants.ID_COLUMN; import static org.folio.repository.titles.TitlesTableConstants.NAME_COLUMN; import static org.folio.repository.titles.TitlesTableConstants.TITLES_TABLE_NAME; -import static org.folio.rest.impl.TitlesTestData.STUB_MANAGED_TITLE_ID; -import static org.folio.rest.impl.TitlesTestData.STUB_MANAGED_TITLE_ID_2; -import static org.folio.test.util.TestUtil.STUB_TENANT; -import static org.folio.test.util.TestUtil.readFile; +import static org.folio.util.TestUtil.STUB_TENANT; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.matching.RegexPattern; -import com.github.tomakehurst.wiremock.matching.UrlPathPattern; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Tuple; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.db.RowSetUtils; import org.folio.repository.SqlQueryHelper; import org.folio.repository.titles.DbTitle; import org.folio.rest.persist.PostgresClient; +@UtilityClass public final class TitlesTestUtil { - private TitlesTestUtil() { } - public static List<DbTitle> getTitles(Vertx vertx) { CompletableFuture<List<DbTitle>> future = new CompletableFuture<>(); String query = prepareQuery(SqlQueryHelper.selectQuery(), titlesTestTable()); @@ -53,12 +43,12 @@ public static void saveTitle(DbTitle dbTitle, Vertx vertx) { future.join(); } - public static DbTitle buildTitle(String id, String credentialsId, String name) { - return buildResource(Long.valueOf(id), toUUID(credentialsId), name); + public static DbTitle buildTitle(int id, String credentialsId, String name) { + return buildResource(id, toUUID(credentialsId), name); } - private static DbTitle buildResource(Long id, UUID credentialsId, String name) { - return DbTitle.builder().id(id).credentialsId(credentialsId).name(name).build(); + private static DbTitle buildResource(int id, UUID credentialsId, String name) { + return DbTitle.builder().id((long) id).credentialsId(credentialsId).name(name).build(); } private static DbTitle mapDbTitle(Row row) { @@ -69,17 +59,6 @@ private static DbTitle mapDbTitle(Row row) { .build(); } - public static void mockGetTitles() throws IOException, URISyntaxException { - String stubResponseFile = "responses/rmapi/titles/get-title-by-id-response.json"; - stubFor(get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/TEST_CUSTOMER_ID/titles/" + STUB_MANAGED_TITLE_ID), - true)).willReturn(new ResponseDefinitionBuilder().withBody(readFile(stubResponseFile)))); - - String stubResponseFile2 = "responses/rmapi/titles/get-title-by-id-2-response.json"; - stubFor(get( - new UrlPathPattern(new RegexPattern("/rm/rmaccounts/TEST_CUSTOMER_ID/titles/" + STUB_MANAGED_TITLE_ID_2), - true)).willReturn(new ResponseDefinitionBuilder().withBody(readFile(stubResponseFile2)))); - } - private static String titlesTestTable() { return PostgresClient.convertToPsqlStandard(STUB_TENANT) + "." + TITLES_TABLE_NAME; } diff --git a/src/test/java/org/folio/util/TokenTestUtils.java b/src/test/java/org/folio/util/TokenTestUtils.java deleted file mode 100644 index bf9a70c70..000000000 --- a/src/test/java/org/folio/util/TokenTestUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.folio.util; - -import io.vertx.core.json.JsonObject; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Base64; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -public final class TokenTestUtils { - - private TokenTestUtils() { - - } - - public static String generateToken(String username, String userId) { - JsonObject header = new JsonObject().put("alg", "HS256"); - JsonObject data = new JsonObject().put("sub", username).put("user_id", userId); - byte[] encodedHeader = Base64.getUrlEncoder().encode(header.toString().getBytes()); - byte[] encodedData = Base64.getUrlEncoder().encode(data.toString().getBytes()); - - try { - String message = new String(encodedHeader) + "." + new String(encodedData); - Mac sha = Mac.getInstance("HmacSHA256"); - - SecretKeySpec secretKey = new SecretKeySpec("no-secret".getBytes(), "HmacSHA256"); - sha.init(secretKey); - - byte[] signature = Base64.getUrlEncoder().encode(sha.doFinal(message.getBytes())); - return new String(encodedHeader) + "." + new String(encodedData) + "." + new String(signature); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new UnsupportedOperationException(e); - } - } -} diff --git a/src/test/java/org/folio/util/TransactionIdTestUtil.java b/src/test/java/org/folio/util/TransactionIdTestUtil.java index f2cebc680..f06309e65 100644 --- a/src/test/java/org/folio/util/TransactionIdTestUtil.java +++ b/src/test/java/org/folio/util/TransactionIdTestUtil.java @@ -5,14 +5,16 @@ import static org.folio.repository.holdings.transaction.TransactionIdTableConstants.CREDENTIALS_ID_COLUMN; import static org.folio.repository.holdings.transaction.TransactionIdTableConstants.TRANSACTION_ID_COLUMN; import static org.folio.repository.holdings.transaction.TransactionIdTableConstants.TRANSACTION_ID_TABLE; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Tuple; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.db.RowSetUtils; import org.folio.rest.persist.PostgresClient; +@UtilityClass public class TransactionIdTestUtil { public static void addTransactionId(String credentialsId, String transactionId, Vertx vertx) { diff --git a/src/test/java/org/folio/util/UcCredentialsTestUtil.java b/src/test/java/org/folio/util/UcCredentialsTestUtil.java index 261215f8b..7ce2d5495 100644 --- a/src/test/java/org/folio/util/UcCredentialsTestUtil.java +++ b/src/test/java/org/folio/util/UcCredentialsTestUtil.java @@ -9,16 +9,18 @@ import static org.folio.repository.SqlQueryHelper.selectQuery; import static org.folio.repository.uc.UcCredentialsTableConstants.CLIENT_ID_COLUMN; import static org.folio.repository.uc.UcCredentialsTableConstants.CLIENT_SECRET_COLUMN; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; import io.vertx.sqlclient.Tuple; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.repository.uc.DbUcCredentials; import org.folio.rest.persist.PostgresClient; +@UtilityClass public class UcCredentialsTestUtil { public static final String UC_CREDENTIALS_ENDPOINT = "eholdings/uc-credentials"; @@ -29,8 +31,8 @@ public class UcCredentialsTestUtil { public static void setUpUcCredentials(Vertx vertx) { var future = new CompletableFuture<>(); - var query = - prepareQuery(insertQuery(CLIENT_ID_COLUMN, CLIENT_SECRET_COLUMN), getUcCredentialsTableName(STUB_TENANT)); + var query = prepareQuery(insertQuery(CLIENT_ID_COLUMN, CLIENT_SECRET_COLUMN), + getUcCredentialsTableName(STUB_TENANT)); Tuple params = Tuple.of( STUB_CLIENT_ID, STUB_CLIENT_SECRET diff --git a/src/test/java/org/folio/util/UcSettingsTestUtil.java b/src/test/java/org/folio/util/UcSettingsTestUtil.java index 14bdc5158..54efecb38 100644 --- a/src/test/java/org/folio/util/UcSettingsTestUtil.java +++ b/src/test/java/org/folio/util/UcSettingsTestUtil.java @@ -15,9 +15,9 @@ import static org.folio.repository.uc.UcSettingsTableConstants.START_MONTH_COLUMN; import static org.folio.repository.uc.UcSettingsTableConstants.UC_SETTINGS_TABLE_NAME; import static org.folio.repository.uc.UcSettingsTableConstants.insertUcSettings; -import static org.folio.rest.impl.WireMockTestBase.JOHN_ID; -import static org.folio.rest.impl.WireMockTestBase.JOHN_USERNAME; -import static org.folio.test.util.TestUtil.STUB_TENANT; +import static org.folio.util.TestUtil.STUB_TENANT; +import static org.folio.util.WireMockTestBase.JOHN_ID; +import static org.folio.util.WireMockTestBase.JOHN_USERNAME; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import lombok.experimental.UtilityClass; import org.folio.repository.uc.DbUcSettings; import org.folio.rest.converter.uc.UcSettingsConverter; import org.folio.rest.jaxrs.model.Meta; @@ -37,6 +38,7 @@ import org.folio.rest.persist.PostgresClient; import org.springframework.core.convert.converter.Converter; +@UtilityClass public class UcSettingsTestUtil { public static final String UC_SETTINGS_ENDPOINT = "eholdings/kb-credentials/%s/uc"; diff --git a/src/test/java/org/folio/util/WireMockTestBase.java b/src/test/java/org/folio/util/WireMockTestBase.java new file mode 100644 index 000000000..f10e3c26b --- /dev/null +++ b/src/test/java/org/folio/util/WireMockTestBase.java @@ -0,0 +1,295 @@ +package org.folio.util; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.badRequest; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.put; +import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.serverError; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static org.folio.HttpStatus.SC_FORBIDDEN; +import static org.folio.HttpStatus.SC_NOT_FOUND; +import static org.folio.HttpStatus.SC_OK; +import static org.folio.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.service.locale.LocaleSettingsServiceImpl.LOCALE_ENDPOINT_PATH; +import static org.folio.service.users.UsersLookUpService.CQL_QUERY_PARAM; +import static org.folio.service.users.UsersLookUpService.GROUPS_ENDPOINT; +import static org.folio.service.users.UsersLookUpService.USERS_BY_ID_ENDPOINT; +import static org.folio.service.users.UsersLookUpService.USERS_ENDPOINT; +import static org.folio.util.TestUtil.readFile; + +import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; +import com.github.tomakehurst.wiremock.common.Slf4jNotifier; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import com.github.tomakehurst.wiremock.http.Fault; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import com.github.tomakehurst.wiremock.matching.ContentPattern; +import com.github.tomakehurst.wiremock.matching.RegexPattern; +import com.github.tomakehurst.wiremock.matching.StringValuePattern; +import com.github.tomakehurst.wiremock.matching.UrlPathPattern; +import com.github.tomakehurst.wiremock.matching.UrlPattern; +import io.restassured.http.Header; +import io.vertx.core.json.Json; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import org.folio.client.uc.model.UcAuthToken; +import org.folio.holdingsiq.model.Configuration; +import org.folio.okapi.common.XOkapiHeaders; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** + * Base test class for tests that use wiremock and vertx http servers, + * test that inherits this class must use VertxUnitRunner as test runner. + */ +@ExtendWith(TestStartLoggingExtension.class) +public abstract class WireMockTestBase extends RmApiConstants { + + // User IDs + public static final String USER_1 = "88888888-8888-4888-8888-888888888888"; + public static final String USER_NOT_FOUND = "22222222-2222-4222-2222-222222222222"; + public static final String USER_FORBIDDEN = "33333333-3333-4333-3333-333333333333"; + public static final String JOHN_ID = "47d9ca93-9c82-4d6a-8d7f-7a73963086b9"; + public static final String JOHN_GROUP_ID = "b4b5e97a-0a99-4db9-97df-4fdf406ec74d"; + public static final String JOHN_USERNAME = "john_doe"; + public static final String JANE_ID = "781fce7d-5cf5-490d-ad89-a3d192eb526c"; + public static final String JANE_GROUP_ID = "4bb563d9-3f9d-4e1e-8d1d-04e75666d68f"; + + // User ID headers + public static final Header JOHN_USER_ID_HEADER = new Header(XOkapiHeaders.USER_ID, JOHN_ID); + public static final Header JANE_USER_ID_HEADER = new Header(XOkapiHeaders.USER_ID, JANE_ID); + public static final Header USER_NOT_FOUND_USER_ID_HEADER = new Header(XOkapiHeaders.USER_ID, USER_NOT_FOUND); + + @RegisterExtension + public static WireMockExtension wm = WireMockExtension.newInstance() + .options(WireMockConfiguration.wireMockConfig() + .dynamicPort() + .notifier(new Slf4jNotifier(true))).build(); + + // Stub response files + private static final String USERDATA_INFO_STUB_FILE = "responses/userlookup/mock_user_response_200.json"; + private static final String USERDATA_JOHN_STUB_FILE = "responses/userlookup/mock_user_response_2_200.json"; + private static final String USERDATA_COLLECTION_INFO_STUB_FILE = + "responses/userlookup/mock_user_collection_response_200.json"; + private static final String GROUP_INFO_STUB_FILE = "responses/userlookup/mock_group_collection_response_200.json"; + + public static void mockGet(StringValuePattern urlPattern, String responseBody) { + wm.stubFor(get(urlPathPattern(urlPattern)) + .willReturn(aResponse() + .withStatus(SC_OK) + .withBody(responseBody))); + } + + public static void mockGet(StringValuePattern urlPattern, + Map<String, StringValuePattern> paramsMatching, + String responseBody) { + var mappingBuilder = get(urlPathPattern(urlPattern)); + paramsMatching.forEach(mappingBuilder::withQueryParam); + wm.stubFor(mappingBuilder + .willReturn(aResponse() + .withStatus(SC_OK) + .withBody(responseBody))); + } + + public static void mockGet(StringValuePattern urlPattern, int status) { + wm.stubFor(get(urlPathPattern(urlPattern)) + .willReturn(new ResponseDefinitionBuilder().withStatus(status))); + } + + public static void mockGet(StringValuePattern urlPattern, String responseBody, int status) { + wm.stubFor(get(urlPathPattern(urlPattern)) + .willReturn(aResponse() + .withStatus(status) + .withBody(responseBody))); + } + + public static void mockPost(StringValuePattern urlPattern, String responseBody, int status) { + wm.stubFor(post(urlPathPattern(urlPattern)) + .willReturn(aResponse() + .withBody(responseBody) + .withStatus(status))); + } + + public static void mockPost(StringValuePattern urlPattern, ContentPattern<?> bodyPattern, + String responseBody, int status) { + wm.stubFor(post(urlPathPattern(urlPattern)) + .withRequestBody(bodyPattern) + .willReturn(aResponse() + .withBody(responseBody) + .withStatus(status))); + } + + public static void mockPut(StringValuePattern urlPattern, ContentPattern<?> bodyPattern, int status) { + wm.stubFor(put(urlPathPattern(urlPattern)) + .withRequestBody(bodyPattern) + .willReturn(new ResponseDefinitionBuilder() + .withStatus(status))); + } + + public static void mockPut(StringValuePattern urlPattern, int status) { + wm.stubFor(put(urlPathPattern(urlPattern)) + .willReturn(new ResponseDefinitionBuilder() + .withStatus(status))); + } + + public static void mockPut(StringValuePattern urlPattern, String responseBody, int status) { + wm.stubFor(put(urlPathPattern(urlPattern)) + .willReturn(aResponse() + .withBody(responseBody) + .withStatus(status))); + } + + public static void verifyPut(StringValuePattern urlPattern, ContentPattern<?> bodyPattern) { + verifyPut(urlPattern, bodyPattern, 1); + } + + public static void verifyPut(StringValuePattern urlPattern, ContentPattern<?> bodyPattern, int count) { + wm.verify(count, putRequestedFor(urlPathPattern(urlPattern)).withRequestBody(bodyPattern)); + } + + public static void verifyPut(StringValuePattern urlPattern, int count) { + wm.verify(count, putRequestedFor(urlPathPattern(urlPattern))); + } + + public static void verifyPut(UrlPattern urlPattern, int count) { + wm.verify(count, putRequestedFor(urlPattern)); + } + + public static void verifyGet(StringValuePattern urlPattern, int count) { + wm.verify(count, getRequestedFor(urlPathPattern(urlPattern))); + } + + public static void verifyPost(StringValuePattern urlPattern, int count) { + wm.verify(count, postRequestedFor(urlPathPattern(urlPattern))); + } + + public static void mockResponseList(UrlPathPattern urlPattern, ResponseDefinitionBuilder... responses) { + int scenarioStep = 0; + String scenarioName = "Scenario -" + UUID.randomUUID(); + for (ResponseDefinitionBuilder response : responses) { + if (scenarioStep == 0) { + wm.stubFor( + get(urlPattern) + .inScenario(scenarioName) + .willSetStateTo(String.valueOf(++scenarioStep)) + .willReturn(response)); + } else { + wm.stubFor( + get(urlPattern) + .inScenario(scenarioName) + .whenScenarioStateIs(String.valueOf(scenarioStep)) + .willSetStateTo(String.valueOf(++scenarioStep)) + .willReturn(response)); + } + } + } + + public Configuration getStubConfiguration() { + return Configuration.builder() + .url(wm.baseUrl()) + .customerId(STUB_CUSTOMER_ID) + .apiKey(STUB_API_KEY) + .build(); + } + + protected String getWiremockUrl() { + return wm.baseUrl(); + } + + protected void mockSuccessfulLocaleResponse() { + mockSuccessfulLocaleResponse("responses/configuration/locale-settings.json"); + } + + protected void mockSuccessfulLocaleResponse(String configFileName) { + wm.stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) + .willReturn(ok(readFile(configFileName)))); + } + + protected void mockFailedLocaleResponse() { + wm.stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) + .willReturn(badRequest())); + } + + protected void mockLocaleResponseWithInvalidJson() { + wm.stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) + .willReturn(ok("{ invalid json }"))); + } + + protected void mockLocaleResponseWithEmptyBody() { + wm.stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) + .willReturn(ok())); + } + + protected void mockLocaleResponseWithServerError() { + wm.stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) + .willReturn(serverError())); + } + + protected void mockLocaleResponseWithNetworkError() { + wm.stubFor(get(urlPathEqualTo(LOCALE_ENDPOINT_PATH)) + .willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER))); + } + + protected void mockUsers() { + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(JOHN_ID)), readFile(USERDATA_JOHN_STUB_FILE)); + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(JANE_ID)), readFile(USERDATA_INFO_STUB_FILE)); + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(USER_1)), readFile(USERDATA_INFO_STUB_FILE)); + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(USER_NOT_FOUND)), SC_NOT_FOUND); + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(USER_FORBIDDEN)), SC_FORBIDDEN); + mockGet(equalTo(USERS_ENDPOINT), Map.of(CQL_QUERY_PARAM, matching("id.*")), + readFile(USERDATA_COLLECTION_INFO_STUB_FILE)); + + mockGet(equalTo(GROUPS_ENDPOINT), Map.of(CQL_QUERY_PARAM, matching("id.*")), readFile(GROUP_INFO_STUB_FILE)); + } + + protected String cqlQueryConverter(List<String> ids) { + return "id=(" + ids.stream() + .map(StringUtil::cqlEncode).collect(Collectors.joining(" OR ")) + ")"; + } + + protected void mockUserById(String id) { + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(id)), + readFile(USERDATA_INFO_STUB_FILE)); + } + + protected void mockUserNotFound(String id) { + mockGet(equalTo(USERS_BY_ID_ENDPOINT.formatted(id)), SC_NOT_FOUND); + } + + protected void mockAuthToken() { + var stubToken = new UcAuthToken("access_token", "Bearer", 3600L, "openid"); + mockPost(matching("/oauth-proxy/token"), Json.encode(stubToken), SC_OK); + } + + protected void mockVerifyValidCredentialsRequest() { + mockGet(matching(RM_ACCOUNTS_BASE_URL + ".*"), "{\"totalResults\": 0, \"vendors\": []}"); + } + + protected void mockVerifyFailedCredentialsRequest() { + mockGet(matching(RM_ACCOUNTS_BASE_URL + ".*"), SC_UNAUTHORIZED); + } + + @BeforeEach + void setUp() { + mockUsers(); + } + + @BeforeAll + static void beforeAll() { + System.setProperty("kb.ebsco.uc.auth.url", wm.baseUrl()); + } + + private static UrlPathPattern urlPathPattern(StringValuePattern urlPattern) { + return new UrlPathPattern(urlPattern, urlPattern instanceof RegexPattern); + } +} diff --git a/src/test/resources/requests/kb-ebsco/package/put-package-custom-multiple-attributes.json b/src/test/resources/requests/kb-ebsco/package/put-package-custom-multiple-attributes.json index 0bc7f2284..391a91993 100644 --- a/src/test/resources/requests/kb-ebsco/package/put-package-custom-multiple-attributes.json +++ b/src/test/resources/requests/kb-ebsco/package/put-package-custom-multiple-attributes.json @@ -10,10 +10,13 @@ "isCustom": true, "isSelected": true, "name": "name of the ages forever and ever", - "visibilityData": { - "isHidden": true, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": true, + "reason": "Hidden by customer" + } + ], "allowKbToAddTitles": true, "proxy": { "id": "<n>", diff --git a/src/test/resources/requests/kb-ebsco/package/put-package-custom-with-access-type.json b/src/test/resources/requests/kb-ebsco/package/put-package-custom-with-access-type.json index 32ac1781b..196f4a4f4 100644 --- a/src/test/resources/requests/kb-ebsco/package/put-package-custom-with-access-type.json +++ b/src/test/resources/requests/kb-ebsco/package/put-package-custom-with-access-type.json @@ -11,10 +11,13 @@ "isCustom": true, "isSelected": true, "name": "name of the ages forever and ever", - "visibilityData": { - "isHidden": true, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": true, + "reason": "Hidden by customer" + } + ], "allowKbToAddTitles": true, "proxy": { "id": "<n>", diff --git a/src/test/resources/requests/kb-ebsco/package/put-package-not-selected-non-empty-fields.json b/src/test/resources/requests/kb-ebsco/package/put-package-not-selected-non-empty-fields.json index 79fc3b692..b98491067 100644 --- a/src/test/resources/requests/kb-ebsco/package/put-package-not-selected-non-empty-fields.json +++ b/src/test/resources/requests/kb-ebsco/package/put-package-not-selected-non-empty-fields.json @@ -9,10 +9,13 @@ "isSelected": false, "isCustom":false, "allowKbToAddTitles": false, - "visibilityData": { - "isHidden": true, - "reason": "" - } + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ] } } } diff --git a/src/test/resources/requests/kb-ebsco/package/put-package-selected-with-access-type.json b/src/test/resources/requests/kb-ebsco/package/put-package-selected-with-access-type.json index 802f846bd..07c33e257 100644 --- a/src/test/resources/requests/kb-ebsco/package/put-package-selected-with-access-type.json +++ b/src/test/resources/requests/kb-ebsco/package/put-package-selected-with-access-type.json @@ -12,10 +12,13 @@ "isSelected": true, "isFullPackage": true, "name": "name of the ages forever and ever", - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": true, + "reason": "Hidden by customer" + } + ], "allowKbToAddTitles": false, "proxy": { "id": "<n>", diff --git a/src/test/resources/requests/kb-ebsco/package/put-package-selected.json b/src/test/resources/requests/kb-ebsco/package/put-package-selected.json index a6a24174e..cbba44641 100644 --- a/src/test/resources/requests/kb-ebsco/package/put-package-selected.json +++ b/src/test/resources/requests/kb-ebsco/package/put-package-selected.json @@ -7,14 +7,37 @@ "beginCoverage": "2003-01-01", "endCoverage": "2004-01-01" }, + "customDescription": "Custom description", + "customAltNames": [ + { + "altName": "Custom Alternate Name1" + }, + { + "id": 1, + "altName": "Custom Alternate Name2" + } + ], + "customDisplayName": "Custome display name", "isCustom": false, "isSelected": true, "isFullPackage": true, + "isFreeAccess": true, "name": "name of the ages forever and ever", - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + }, + { + "category": "FTF", + "hidden": true + }, + { + "category": "MARC", + "hidden": true + } + ], "allowKbToAddTitles": false, "proxy": { "id": "<n>", diff --git a/src/test/resources/requests/kb-ebsco/package/put-package-with-invalid-access-type.json b/src/test/resources/requests/kb-ebsco/package/put-package-with-invalid-access-type.json index cad83e58f..cbdf9f736 100644 --- a/src/test/resources/requests/kb-ebsco/package/put-package-with-invalid-access-type.json +++ b/src/test/resources/requests/kb-ebsco/package/put-package-with-invalid-access-type.json @@ -11,10 +11,13 @@ "isCustom": true, "isSelected": true, "name": "name of the ages forever and ever", - "visibilityData": { - "isHidden": true, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "allowKbToAddTitles": true, "proxy": { "id": "<n>", diff --git a/src/test/resources/requests/kb-ebsco/package/put-package-with-not-existed-access-type.json b/src/test/resources/requests/kb-ebsco/package/put-package-with-not-existed-access-type.json index b22680979..2c056d88b 100644 --- a/src/test/resources/requests/kb-ebsco/package/put-package-with-not-existed-access-type.json +++ b/src/test/resources/requests/kb-ebsco/package/put-package-with-not-existed-access-type.json @@ -11,10 +11,13 @@ "isCustom": true, "isSelected": true, "name": "name of the ages forever and ever", - "visibilityData": { - "isHidden": true, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "allowKbToAddTitles": true, "proxy": { "id": "<n>", diff --git a/src/test/resources/requests/rmapi/packages/put-package-custom.json b/src/test/resources/requests/rmapi/packages/put-package-custom.json index dfc52f16a..88555a32d 100644 --- a/src/test/resources/requests/rmapi/packages/put-package-custom.json +++ b/src/test/resources/requests/rmapi/packages/put-package-custom.json @@ -1,11 +1,28 @@ { + "packageName": "name of the ages forever and ever", "contentType": 8, "isSelected": true, + "visibility": [ + { + "category": "PF", + "hidden": true, + "reason": "Hidden by customer" + } + ], + "customDescription": null, + "url": null, + "isFullPackage": null, + "allowEbscoToAddTitles": null, "customCoverage": { "beginCoverage": "2003-01-01", "endCoverage": "2004-01-01" }, + "proxy": { + "id": "<n>", + "inherited": false + }, "packageToken": null, - "isHidden": true, - "packageName": "name of the ages forever and ever" -} + "customAltNames": [], + "customDisplayName": null, + "packageFreeAccess": null +} \ No newline at end of file diff --git a/src/test/resources/requests/rmapi/packages/put-package-is-selected.json b/src/test/resources/requests/rmapi/packages/put-package-is-selected.json index 0cf815691..d9a64bf30 100644 --- a/src/test/resources/requests/rmapi/packages/put-package-is-selected.json +++ b/src/test/resources/requests/rmapi/packages/put-package-is-selected.json @@ -1,17 +1,47 @@ { - "packageName" : null, - "contentType" : null, + "packageName": null, + "contentType": null, + "isSelected": true, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + }, + { + "category": "FTF", + "hidden": true, + "reason": null + }, + { + "category": "MARC", + "hidden": true, + "reason": null + } + ], + "customDescription": "Custom description", + "url": null, + "isFullPackage": true, + "allowEbscoToAddTitles": false, "customCoverage": { "beginCoverage": "2003-01-01", "endCoverage": "2004-01-01" }, - "isSelected": true, - "isFullPackage": true, - "allowEbscoToAddTitles": false, - "isHidden": false, - "packageToken": null, "proxy": { "id": "<n>", "inherited": false - } -} + }, + "packageToken": null, + "customAltNames": [ + { + "id": null, + "altName": "Custom Alternate Name1" + }, + { + "id": 1, + "altName": "Custom Alternate Name2" + } + ], + "customDisplayName": "Custome display name", + "packageFreeAccess": true +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/export/expected-export-three-items-usd.txt b/src/test/resources/responses/kb-ebsco/export/expected-export-three-items-usd.txt index c09862ffd..90058c5a0 100644 --- a/src/test/resources/responses/kb-ebsco/export/expected-export-three-items-usd.txt +++ b/src/test/resources/responses/kb-ebsco/export/expected-export-three-items-usd.txt @@ -1,4 +1,4 @@ "Title"|"Type"|"Usage"|"Cost"|"Cost_per_use"|"Currency_selected"|"Percentage_of_usage"|"Year_selection"|"Platform" -"A | title"|"Book"|"1"|"0.00"|"0.00"|"USD"|"0 %"|"2019"|"publisher" -"B title"|"Book"|"2"|"100.00"|"50.00"|"USD"|"33 %"|"2019"|"publisher" -"C title"|"Book"|"10"|"200.00"|"20.00"|"USD"|"67 %"|"2019"|"publisher" +"A | title"|"Book"|"1"|"0.00"|"0.00"|"USD"|"4 %"|"2019"|"publisher" +"B title"|"Book"|"2"|"100.00"|"50.00"|"USD"|"8 %"|"2019"|"publisher" +"C title"|"Book"|"10"|"200.00"|"20.00"|"USD"|"38 %"|"2019"|"publisher" diff --git a/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json index c87bbcb02..6e2da3184 100644 --- a/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json +++ b/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id-with-provider.json @@ -1,75 +1,87 @@ { - "data" : { - "id" : "19-3964", - "type" : "packages", - "attributes" : { - "contentType" : "Aggregated Full Text", - "customCoverage" : { - "beginCoverage" : "", - "endCoverage" : "" + "data": { + "id": "19-3964", + "type": "packages", + "attributes": { + "allowKbToAddTitles": false, + "contentType": "Aggregated Full Text", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" }, - "isCustom" : true, - "isSelected" : true, - "name" : "carole and sams test", - "packageId" : 3964, - "packageType" : "Custom", - "providerId" : 19, - "providerName" : "APIDEV CORPORATE CUSTOMER", - "selectedCount" : 6, - "titleCount" : 6, - "visibilityData" : { - "isHidden" : false, - "reason" : "" + "isCustom": true, + "isSelected": true, + "name": "carole and sams test", + "packageId": 3964, + "packageToken": { + "factName": "[[gale.customcode.infocust]]", + "prompt": "res_id=info:sid/gale:", + "helpText": "help text", + "value": "token value" }, - "allowKbToAddTitles" : false, - "packageToken" : { - "factName" : "[[gale.customcode.infocust]]", - "prompt" : "res_id=info:sid/gale:", - "helpText" : "help text", - "value" : "token value" + "packageType": "Custom", + "providerId": 19, + "providerName": "APIDEV CORPORATE CUSTOMER", + "proxy": { + "id": "<n>", + "inherited": true }, - "proxy" : { - "id" : "<n>", - "inherited" : true + "selectedCount": 6, + "tags": { + "tagList": [] + }, + "titleCount": 6, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ], + "visibilityData": { + "isHidden": false, + "reason": "" } }, - "relationships" : { - "resources" : { - "data" : [ ], - "meta" : { - "included" : false + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false } }, - "provider" : { - "data" : { - "type" : "providers", - "id" : "19" + "provider": { + "data": { + "type": "providers", + "id": "19" } } } }, - "included" : [ { - "id" : "19", - "type" : "providers", - "attributes" : { - "name" : "APIDEV CORPORATE CUSTOMER", - "packagesTotal" : 34, - "packagesSelected" : 1, - "supportsCustomPackages" : false, - "proxy" : { - "id" : "<n>", - "inherited" : true - } - }, - "relationships" : { - "packages" : { - "meta" : { - "included" : false + "included": [ + { + "id": "19", + "type": "providers", + "attributes": { + "name": "APIDEV CORPORATE CUSTOMER", + "packagesTotal": 34, + "packagesSelected": 1, + "supportsCustomPackages": false, + "proxy": { + "id": "<n>", + "inherited": true + } + }, + "relationships": { + "packages": { + "meta": { + "included": false + } } } } - } ], - "jsonapi" : { - "version" : "1.0" + ], + "jsonapi": { + "version": "1.0" } -} +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id.json index 4f037ecca..958086721 100644 --- a/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id.json +++ b/src/test/resources/responses/kb-ebsco/packages/expected-package-by-id.json @@ -3,38 +3,44 @@ "id": "19-3964", "type": "packages", "attributes": { - "name": "carole and sams test", - "packageId": 3964, - "isCustom": true, - "providerId": 19, - "providerName": "APIDEV CORPORATE CUSTOMER", - "titleCount": 6, - "isSelected": true, - "selectedCount": 6, - "packageType": "Custom", + "allowKbToAddTitles": false, "contentType": "Aggregated Full Text", "customCoverage": { "beginCoverage": "", "endCoverage": "" }, - "visibilityData": { - "isHidden": false, - "reason": "" + "isCustom": true, + "isSelected": true, + "name": "carole and sams test", + "packageId": 3964, + "packageToken": { + "factName": "[[gale.customcode.infocust]]", + "prompt": "res_id=info:sid/gale:", + "helpText": "help text", + "value": "token value" }, + "packageType": "Custom", + "providerId": 19, + "providerName": "APIDEV CORPORATE CUSTOMER", "proxy": { "id": "<n>", "inherited": true }, - "allowKbToAddTitles": false, - "packageToken": { - "factName": "[[gale.customcode.infocust]]", - "helpText": "help text", - "value": "token value", - "prompt": "res_id=info:sid/gale:" - } + "selectedCount": 6, + "tags": { + "tagList": [] + }, + "titleCount": 6, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ] } }, "jsonapi": { "version": "1.0" } -} +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-five-elements.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-five-elements.json index 2fffc3dc6..f45d98ac8 100644 --- a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-five-elements.json +++ b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-five-elements.json @@ -1,129 +1,265 @@ { - "data" : [ { - "id" : "392-3007", - "type" : "packages", - "attributes" : { - "name" : "American Academy of Family Physicians", - "packageId" : 3007, - "isCustom" : false, - "providerId" : 392, - "providerName" : "American Academy of Family Physicians", - "titleCount" : 3, - "isSelected" : false, - "selectedCount" : 0, - "packageType" : "Variable", - "contentType" : "E-Journal", - "customCoverage" : { - "beginCoverage" : "", - "endCoverage" : "" - }, - "visibilityData" : { - "isHidden" : false, - "reason" : "" - } - } - }, + "data": [ { - "id": "114569-1597443", + "id": "392-3007", "type": "packages", "attributes": { - "name": "American Academy of Orthopaedic Surgeons", - "packageId": 1597443, + "contentType": "E-Journal", + "customAltNames": [ + { + "altName": "Health/Wellness Resource Center" + } + ], + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "customDescription": "Custom Health & Wellness Resource Description example that's modified by a customer", + "customDisplayName": "Family Physicians American Academy", + "isAvailableForSelection": true, "isCustom": false, - "providerId": 114569, - "providerName": "American Academy of Orthopaedic Surgeons", - "titleCount": 108, + "isFreeAccess": false, + "isPrimaryPackage": true, "isSelected": false, - "selectedCount": 0, + "managedAltNames": [ + { + "altName": "Health & Wellness Resource Center Alternative" + } + ], + "managedDescription": "Health & Wellness Resource Description example", + "name": "American Academy of Family Physicians", + "packageId": 3007, "packageType": "Variable", + "providerId": 392, + "providerName": "American Academy of Family Physicians", + "selectedCount": 0, + "titleCount": 3, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } + }, + "provider": { + "meta": { + "included": false + } + } + } + }, + { + "id": "114569-1597443", + "type": "packages", + "attributes": { "contentType": "Aggregated Full Text", + "customAltNames": [], "customCoverage": { "beginCoverage": "", "endCoverage": "" }, + "isCustom": false, + "isSelected": false, + "managedAltNames": [], + "name": "American Academy of Orthopaedic Surgeons", + "packageId": 1597443, + "packageType": "Variable", + "providerId": 114569, + "providerName": "American Academy of Orthopaedic Surgeons", + "selectedCount": 0, + "titleCount": 108, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + }, + { + "category": "MARC", + "hidden": true + } + ], "visibilityData": { - "isHidden": false, + "isHidden": true, "reason": "" } + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } + }, + "provider": { + "meta": { + "included": false + } + } } }, { "id": "554-3943", "type": "packages", "attributes": { - "name": "American Academy of Pediatrics (AAP)", - "packageId": 3943, - "isCustom": false, - "providerId": 554, - "providerName": "American Academy of Pediatrics (AAP)", - "titleCount": 6, - "isSelected": false, - "selectedCount": 0, - "packageType": "Variable", "contentType": "E-Journal", + "customAltNames": [], "customCoverage": { "beginCoverage": "", "endCoverage": "" }, + "isCustom": false, + "isSelected": false, + "managedAltNames": [], + "name": "American Academy of Pediatrics (AAP)", + "packageId": 3943, + "packageType": "Variable", + "providerId": 554, + "providerName": "American Academy of Pediatrics (AAP)", + "selectedCount": 0, + "titleCount": 6, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + }, + { + "category": "FTF", + "hidden": true + }, + { + "category": "MARC", + "hidden": true + } + ], "visibilityData": { - "isHidden": false, + "isHidden": true, "reason": "" } + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } + }, + "provider": { + "meta": { + "included": false + } + } } }, { "id": "554-7566", "type": "packages", "attributes": { - "name": "American Academy of Pediatrics (AAP) eBooks", - "packageId": 7566, - "isCustom": false, - "providerId": 554, - "providerName": "American Academy of Pediatrics (AAP)", - "titleCount": 207, - "isSelected": false, - "selectedCount": 0, - "packageType": "Variable", "contentType": "E-Book", + "customAltNames": [], "customCoverage": { "beginCoverage": "", "endCoverage": "" }, + "isCustom": false, + "isSelected": false, + "managedAltNames": [], + "name": "American Academy of Pediatrics (AAP) eBooks", + "packageId": 7566, + "packageType": "Variable", + "providerId": 554, + "providerName": "American Academy of Pediatrics (AAP)", + "selectedCount": 0, + "titleCount": 207, + "visibility": [ + { + "category": "FTF", + "hidden": false + } + ], "visibilityData": { "isHidden": false, "reason": "" } + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } + }, + "provider": { + "meta": { + "included": false + } + } } }, { "id": "554-19236", "type": "packages", "attributes": { - "name": "American Academy of Pediatrics (KMLA)", - "packageId": 19236, - "isCustom": false, - "providerId": 554, - "providerName": "American Academy of Pediatrics (AAP)", - "titleCount": 6, - "isSelected": false, - "selectedCount": 0, - "packageType": "Complete", "contentType": "E-Journal", + "customAltNames": [], "customCoverage": { "beginCoverage": "", "endCoverage": "" }, + "isCustom": false, + "isSelected": false, + "managedAltNames": [], + "name": "American Academy of Pediatrics (KMLA)", + "packageId": 19236, + "packageType": "Complete", + "providerId": 554, + "providerName": "American Academy of Pediatrics (AAP)", + "selectedCount": 0, + "titleCount": 6, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ], "visibilityData": { "isHidden": false, "reason": "" } + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } + }, + "provider": { + "meta": { + "included": false + } + } } } - ], - "meta" : { - "totalResults" : 414 + ], + "meta": { + "totalResults": 414 }, - "jsonapi" : { - "version" : "1.0" + "jsonapi": { + "version": "1.0" } -} +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element-with-tags.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element-with-tags.json index 92f09846f..fddbb0fcc 100644 --- a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element-with-tags.json +++ b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element-with-tags.json @@ -1,50 +1,56 @@ { - "data" : [ { - "id" : "19-3964", - "type" : "packages", - "attributes" : { - "contentType" : "Online Reference", - "customCoverage" : { - "beginCoverage" : "", - "endCoverage" : "" - }, - "isCustom" : true, - "isSelected" : true, - "name" : "TEST_PACKAGE_NAME", - "packageId" : 3964, - "packageType" : "Custom", - "providerId" : 19, - "providerName" : "TEST_VENDOR_NAME", - "selectedCount" : 5, - "titleCount" : 5, - "visibilityData" : { - "isHidden" : false, - "reason" : "" - }, - "tags" : { - "tagList":[ - "tag one", - "tag 2" + "data": [ + { + "id": "19-3964", + "type": "packages", + "attributes": { + "contentType": "Online Reference", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "isCustom": true, + "isSelected": true, + "name": "TEST_PACKAGE_NAME", + "packageId": 3964, + "packageType": "Custom", + "providerId": 19, + "providerName": "TEST_VENDOR_NAME", + "selectedCount": 5, + "tags": { + "tagList": [ + "tag one", + "tag 2" + ] + }, + "titleCount": 5, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } ] - } - }, - "relationships" : { - "resources" : { - "meta" : { - "included" : false - } }, - "provider" : { - "meta" : { - "included" : false + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } + }, + "provider": { + "meta": { + "included": false + } } } } - } ], - "meta" : { - "totalResults" : 1 + ], + "meta": { + "totalResults": 1 }, - "jsonapi" : { - "version" : "1.0" + "jsonapi": { + "version": "1.0" } } diff --git a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json index 0fef6d07e..26baae3e4 100644 --- a/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json +++ b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json @@ -1,44 +1,54 @@ { - "data" : [ { - "id" : "19-3964", - "type" : "packages", - "attributes" : { - "contentType" : "Online Reference", - "customCoverage" : { - "beginCoverage" : "", - "endCoverage" : "" - }, - "isCustom" : true, - "isSelected" : true, - "name" : "TEST_PACKAGE_NAME", - "packageId" : 3964, - "packageType" : "Custom", - "providerId" : 19, - "providerName" : "TEST_VENDOR_NAME", - "selectedCount" : 5, - "titleCount" : 5, - "visibilityData" : { - "isHidden" : false, - "reason" : "" - } - }, - "relationships" : { - "resources" : { - "meta" : { - "included" : false + "data": [ + { + "id": "19-3964", + "type": "packages", + "attributes": { + "contentType": "Online Reference", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "isCustom": true, + "isSelected": true, + "name": "TEST_PACKAGE_NAME", + "packageId": 3964, + "packageType": "Custom", + "providerId": 19, + "providerName": "TEST_VENDOR_NAME", + "selectedCount": 5, + "titleCount": 5, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ], + "visibilityData": { + "isHidden": false, + "reason": "" } }, - "provider" : { - "meta" : { - "included" : false + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } + }, + "provider": { + "meta": { + "included": false + } } } } - } ], - "meta" : { - "totalResults" : 1 + ], + "meta": { + "totalResults": 1 }, - "jsonapi" : { - "version" : "1.0" + "jsonapi": { + "version": "1.0" } -} +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/packages/get-created-package-response.json b/src/test/resources/responses/kb-ebsco/packages/get-created-package-response.json deleted file mode 100644 index 7b38ea338..000000000 --- a/src/test/resources/responses/kb-ebsco/packages/get-created-package-response.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "data" : { - "id" : "19-3964", - "type" : "packages", - "attributes" : { - "contentType" : "Aggregated Full Text", - "customCoverage" : { - "beginCoverage" : "", - "endCoverage" : "" - }, - "isCustom" : false, - "isSelected" : false, - "name" : "EBSCO Biotechnology Collection: India", - "packageId" : 3964, - "packageType" : "Complete", - "providerId" : 19, - "providerName" : "EBSCO", - "selectedCount" : 0, - "titleCount" : 156, - "visibilityData" : { - "isHidden" : false, - "reason" : "" - }, - "allowKbToAddTitles" : false, - "proxy" : { - "id" : "<n>", - "inherited" : true - }, - "tags": { - "tagList": [] - } - }, - "relationships" : { - "resources" : { - "meta" : { - "included" : false - } - }, - "provider" : { - "meta" : { - "included" : false - } - } - } - }, - "jsonapi" : { - "version" : "1.0" - } -} diff --git a/src/test/resources/responses/kb-ebsco/providers/expected-provider-with-packages.json b/src/test/resources/responses/kb-ebsco/providers/expected-provider-with-packages.json index 1784514dc..d61d12668 100644 --- a/src/test/resources/responses/kb-ebsco/providers/expected-provider-with-packages.json +++ b/src/test/resources/responses/kb-ebsco/providers/expected-provider-with-packages.json @@ -51,10 +51,13 @@ "providerName": "TEST_VENDOR_NAME", "selectedCount": 5, "titleCount": 5, - "visibilityData": { - "isHidden": false, - "reason": "" - } + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ] }, "relationships": { "resources": { @@ -74,4 +77,4 @@ "jsonapi": { "version": "1.0" } -} +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json index 1f66bad76..17000ce26 100644 --- a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json +++ b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-all-objects.json @@ -72,9 +72,9 @@ ], "customCoverages": [], "proxy": { + "proxiedUrl": "https://example.com", "id": "<n>", - "inherited": true, - "proxiedUrl": "https://example.com" + "inherited": true }, "tags": { "tagList": [] @@ -186,6 +186,7 @@ "id": "19-3964", "type": "packages", "attributes": { + "allowKbToAddTitles": false, "contentType": "Mixed Content", "customCoverage": { "beginCoverage": "2018-08-13", @@ -198,16 +199,22 @@ "packageType": "Variable", "providerId": 19, "providerName": "ABC-CLIO", + "proxy": { + "id": "Proxy-ID-123", + "inherited": true + }, "selectedCount": 9590, "titleCount": 9590, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ], "visibilityData": { - "isHidden": true, + "isHidden": false, "reason": "" - }, - "allowKbToAddTitles": false, - "proxy": { - "id": "Proxy-ID-123", - "inherited": true } }, "relationships": { @@ -228,4 +235,4 @@ "jsonapi": { "version": "1.0" } -} +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json index 09726bd32..9b1910c82 100644 --- a/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json +++ b/src/test/resources/responses/kb-ebsco/resources/expected-resource-by-id-with-package.json @@ -72,9 +72,9 @@ ], "customCoverages": [], "proxy": { + "proxiedUrl": "https://example.com", "id": "<n>", - "inherited": true, - "proxiedUrl": "https://example.com" + "inherited": true }, "tags": { "tagList": [] @@ -109,6 +109,7 @@ "id": "19-3964", "type": "packages", "attributes": { + "allowKbToAddTitles": false, "contentType": "Mixed Content", "customCoverage": { "beginCoverage": "2018-08-13", @@ -121,16 +122,22 @@ "packageType": "Variable", "providerId": 19, "providerName": "ABC-CLIO", + "proxy": { + "id": "Proxy-ID-123", + "inherited": true + }, "selectedCount": 9590, "titleCount": 9590, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ], "visibilityData": { - "isHidden": true, + "isHidden": false, "reason": "" - }, - "allowKbToAddTitles": false, - "proxy": { - "id": "Proxy-ID-123", - "inherited": true } }, "relationships": { @@ -151,4 +158,4 @@ "jsonapi": { "version": "1.0" } -} +} \ No newline at end of file diff --git a/src/test/resources/responses/kb-ebsco/resources/expected-tagged-resources.json b/src/test/resources/responses/kb-ebsco/resources/expected-tagged-resources.json deleted file mode 100644 index c29b98c93..000000000 --- a/src/test/resources/responses/kb-ebsco/resources/expected-tagged-resources.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "data": [{ - "id": "19-3964-762169", - "type": "resources", - "attributes": { - "isPeerReviewed": false, - "isTitleCustom": false, - "publisherName": "Praeger", - "titleId": 762169, - "contributors": [ - { - "type": "author", - "contributor": "Beeman, William O." - } - ], - "identifiers": [ - { - "id": "978-0-275-98214-0", - "subtype": "Print", - "type": "ISBN" - }, - { - "id": "978-0-313-06800-3", - "subtype": "Online", - "type": "ISBN" - }, - { - "id": "978-1-282-40979-8", - "subtype": "Online", - "type": "ISBN" - } - ], - "name": "\"Great Satan\" Vs. the \"Mad Mullahs\": How the United States and Iran Demonize Each Other", - "publicationType": "Book", - "subjects": [ - { - "subject": "SOCIAL SCIENCE / Ethnic Studies / General", - "type": "BISAC" - } - ], - "customEmbargoPeriod": { - "embargoValue": 0 - }, - "isPackageCustom": false, - "isSelected": true, - "isTokenNeeded": false, - "locationId": 2863717, - "managedEmbargoPeriod": { - "embargoValue": 0 - }, - "packageId": "19-3964", - "packageName": "ABC-CLIO eBook Collection", - "url": "https://publisher.abc-clio.com/9780313068003/", - "providerId": 19, - "providerName": "ABC-CLIO", - "visibilityData": { - "isHidden": true, - "reason": "" - }, - "managedCoverages": [ - { - "beginCoverage": "2005-01-01", - "endCoverage": "2005-12-31" - } - ], - "customCoverages": [], - "proxy": { - "id": "<n>", - "inherited": true - }, - "tags": { - "tagList": [ - "tag one", - "tag 2" - ] - } - }, - "relationships": { - "provider": { - "meta": { - "included": false - } - }, - "title": { - "meta": { - "included": false - } - }, - "package": { - "meta": { - "included": false - } - } - } - }], - "meta": { - "totalResults": 1 - }, - "jsonapi": { - "version": "1.0" - } -} diff --git a/src/test/resources/responses/rmapi/holdings/status/get-status-in-progress.json b/src/test/resources/responses/rmapi/holdings/status/get-status-in-progress.json deleted file mode 100644 index 1f1e2af51..000000000 --- a/src/test/resources/responses/rmapi/holdings/status/get-status-in-progress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "status": "In progress", - "created": "1999-12-31 23:59:59", - "totalCount": 2 -} diff --git a/src/test/resources/responses/rmapi/packages/get-created-package-response.json b/src/test/resources/responses/rmapi/packages/get-created-package-response.json index ffbdab9f4..ef68a6e7e 100644 --- a/src/test/resources/responses/rmapi/packages/get-created-package-response.json +++ b/src/test/resources/responses/rmapi/packages/get-created-package-response.json @@ -1,52 +1,55 @@ { - "data" : { - "id" : "19-3964", - "type" : "packages", - "attributes" : { - "contentType" : "E-Journal", - "customCoverage" : { - "beginCoverage" : "", - "endCoverage" : "" + "data": { + "id": "19-3964", + "type": "packages", + "attributes": { + "contentType": "E-Journal", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" }, - "isCustom" : true, - "isSelected" : true, - "name" : "carole and sams test", - "packageId" : 3964, - "packageType" : "Custom", - "providerId" : 19, - "providerName" : "APIDEV CORPORATE CUSTOMER", - "selectedCount" : 6, - "titleCount" : 6, - "visibilityData" : { - "isHidden" : false, - "reason" : "" - }, - "allowKbToAddTitles" : false, - "packageToken" : { - "factName" : "[[gale.customcode.infocust]]", - "prompt" : "res_id=info:sid/gale:", - "helpText" : "help text", - "value" : "token value" + "isCustom": true, + "isSelected": true, + "name": "carole and sams test", + "packageId": 3964, + "packageType": "Custom", + "providerId": 19, + "providerName": "APIDEV CORPORATE CUSTOMER", + "selectedCount": 6, + "titleCount": 6, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], + "allowKbToAddTitles": false, + "packageToken": { + "factName": "[[gale.customcode.infocust]]", + "prompt": "res_id=info:sid/gale:", + "helpText": "help text", + "value": "token value" }, - "proxy" : { - "id" : "<n>", - "inherited" : true + "proxy": { + "id": "<n>", + "inherited": true } }, - "relationships" : { - "resources" : { - "meta" : { - "included" : false + "relationships": { + "resources": { + "meta": { + "included": false } }, - "provider" : { - "meta" : { - "included" : false + "provider": { + "meta": { + "included": false } } } }, - "jsonapi" : { - "version" : "1.0" + "jsonapi": { + "version": "1.0" } } diff --git a/src/test/resources/responses/rmapi/packages/get-custom-package-by-id-response.json b/src/test/resources/responses/rmapi/packages/get-custom-package-by-id-response.json index 31f44aba4..590843736 100644 --- a/src/test/resources/responses/rmapi/packages/get-custom-package-by-id-response.json +++ b/src/test/resources/responses/rmapi/packages/get-custom-package-by-id-response.json @@ -1,15 +1,18 @@ { - "packageId": 3964, + "listId": 3964, "packageName": "carole and sams test", "isCustom": true, "vendorId": 19, "vendorName": "APIDEV CORPORATE CUSTOMER", "titleCount": 6, "isSelected": true, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "selectedCount": 6, "isTokenNeeded": false, "contentType": "AggregatedFullText", diff --git a/src/test/resources/responses/rmapi/packages/get-package-by-id-2-response.json b/src/test/resources/responses/rmapi/packages/get-package-by-id-2-response.json index 2a27a5dd9..ca38f226b 100644 --- a/src/test/resources/responses/rmapi/packages/get-package-by-id-2-response.json +++ b/src/test/resources/responses/rmapi/packages/get-package-by-id-2-response.json @@ -1,15 +1,18 @@ { - "packageId": 13964, + "listId": 13964, "packageName": "America and World War I: American Military Camp Newspapers", "isCustom": false, "vendorId": 19, "vendorName": "EBSCO", "titleCount": 156, "isSelected": false, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "selectedCount": 0, "isTokenNeeded": false, "contentType": "AggregatedFullText", diff --git a/src/test/resources/responses/rmapi/packages/get-package-by-id-for-resource.json b/src/test/resources/responses/rmapi/packages/get-package-by-id-for-resource.json index 31b23b22c..2b4fa343a 100644 --- a/src/test/resources/responses/rmapi/packages/get-package-by-id-for-resource.json +++ b/src/test/resources/responses/rmapi/packages/get-package-by-id-for-resource.json @@ -1,15 +1,18 @@ { - "packageId": 3964, + "listId": 3964, "packageName": "ABC-CLIO eBook Collection", "isCustom": false, "vendorId": 19, "vendorName": "ABC-CLIO", "titleCount": 9590, "isSelected": true, - "visibilityData": { - "isHidden": true, - "reason": "Hidden by Customer" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "selectedCount": 9590, "isTokenNeeded": false, "contentType": "mixedcontent", diff --git a/src/test/resources/responses/rmapi/packages/get-package-by-id-response.json b/src/test/resources/responses/rmapi/packages/get-package-by-id-response.json index 457efb8f9..552c12c5e 100644 --- a/src/test/resources/responses/rmapi/packages/get-package-by-id-response.json +++ b/src/test/resources/responses/rmapi/packages/get-package-by-id-response.json @@ -1,15 +1,18 @@ { - "packageId": 3964, + "listId": 3964, "packageName": "EBSCO Biotechnology Collection: India", "isCustom": false, "vendorId": 19, "vendorName": "EBSCO", "titleCount": 156, "isSelected": false, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "selectedCount": 0, "isTokenNeeded": false, "contentType": "AggregatedFullText", diff --git a/src/test/resources/responses/rmapi/packages/get-packages-by-provider-id.json b/src/test/resources/responses/rmapi/packages/get-packages-by-provider-id.json index b1402c817..1b7e2f22a 100644 --- a/src/test/resources/responses/rmapi/packages/get-packages-by-provider-id.json +++ b/src/test/resources/responses/rmapi/packages/get-packages-by-provider-id.json @@ -2,17 +2,20 @@ "totalResults": 1, "packagesList": [ { - "packageId": 3964, + "listId": 3964, "packageName": "TEST_PACKAGE_NAME", "isCustom": true, "vendorId": 19, "vendorName": "TEST_VENDOR_NAME", "titleCount": 5, "isSelected": true, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "selectedCount": 5, "isTokenNeeded": false, "contentType": "OnlineReference", diff --git a/src/test/resources/responses/rmapi/packages/get-packages-response.json b/src/test/resources/responses/rmapi/packages/get-packages-response.json index 7e5bf99d9..76faeaa8c 100644 --- a/src/test/resources/responses/rmapi/packages/get-packages-response.json +++ b/src/test/resources/responses/rmapi/packages/get-packages-response.json @@ -2,17 +2,42 @@ "totalResults": 414, "packagesList": [ { - "packageId": 3007, + "listId": 3007, "packageName": "American Academy of Family Physicians", + "customDisplayName": "Family Physicians American Academy", + "managedAltNames": [ + "Health & Wellness Resource Center Alternative" + ], + "customAltNames": [ + "Health/Wellness Resource Center" + ], + "managedDescription": "Health & Wellness Resource Description example", + "customDescription": "Custom Health & Wellness Resource Description example that's modified by a customer", + "packageFreeAccess": false, "isCustom": false, "vendorId": 392, + "availableForSelection": true, "vendorName": "American Academy of Family Physicians", "titleCount": 3, "isSelected": false, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], + "subjectAssociations": [ + { + "id": 35408, + "parentId": 35407, + "schemaId": 3, + "name": "Technology", + "isCustom": false + } + ], + "consortia": "string", + "isPrimaryPackage": true, "selectedCount": 0, "isTokenNeeded": false, "contentType": "EJournal", @@ -33,17 +58,24 @@ } }, { - "packageId": 1597443, + "listId": 1597443, "packageName": "American Academy of Orthopaedic Surgeons", "isCustom": false, "vendorId": 114569, "vendorName": "American Academy of Orthopaedic Surgeons", "titleCount": 108, "isSelected": false, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + }, + { + "category": "MARC", + "hidden": true + } + ], "selectedCount": 0, "isTokenNeeded": false, "contentType": "AggregatedFullText", @@ -54,17 +86,28 @@ "packageType": "Variable" }, { - "packageId": 3943, + "listId": 3943, "packageName": "American Academy of Pediatrics (AAP)", "isCustom": false, "vendorId": 554, "vendorName": "American Academy of Pediatrics (AAP)", "titleCount": 6, "isSelected": false, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + }, + { + "category": "FTF", + "hidden": true + }, + { + "category": "MARC", + "hidden": true + } + ], "selectedCount": 0, "isTokenNeeded": false, "contentType": "EJournal", @@ -75,17 +118,19 @@ "packageType": "Variable" }, { - "packageId": 7566, + "listId": 7566, "packageName": "American Academy of Pediatrics (AAP) eBooks", "isCustom": false, "vendorId": 554, "vendorName": "American Academy of Pediatrics (AAP)", "titleCount": 207, "isSelected": false, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "FTF", + "hidden": false + } + ], "selectedCount": 0, "isTokenNeeded": false, "contentType": "EBook", @@ -96,17 +141,20 @@ "packageType": "Variable" }, { - "packageId": 19236, + "listId": 19236, "packageName": "American Academy of Pediatrics (KMLA)", "isCustom": false, "vendorId": 554, "vendorName": "American Academy of Pediatrics (AAP)", "titleCount": 6, "isSelected": false, - "visibilityData": { - "isHidden": false, - "reason": "" - }, + "visibility": [ + { + "category": "PF", + "hidden": false, + "reason": "Hidden by customer" + } + ], "selectedCount": 0, "isTokenNeeded": false, "contentType": "EJournal", diff --git a/src/test/resources/responses/rmapi/packages/post-package-request.json b/src/test/resources/responses/rmapi/packages/post-package-request.json deleted file mode 100644 index d5d4da277..000000000 --- a/src/test/resources/responses/rmapi/packages/post-package-request.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "data":{ - "type":"packages", - "attributes":{ - "name": "TEST_NAME", - "contentType": "E-Journal", - "customCoverage":{ - "beginCoverage": "2017-12-23", - "endCoverage": "2018-03-30" - } - } - } -} diff --git a/src/test/resources/test-application.properties b/src/test/resources/test-application.properties index d1a1146b1..11747e7bb 100644 --- a/src/test/resources/test-application.properties +++ b/src/test/resources/test-application.properties @@ -47,3 +47,4 @@ kb.ebsco.custom.labels.value.length.max=100 # HoldingsIQ search type properties kb.ebsco.search-type.titles=advanced kb.ebsco.search-type.packages=advanced +kb-ebsco.highlight-tag=mark