From 555488b310a9e02b8c5be67f4e3807c3791e63d1 Mon Sep 17 00:00:00 2001 From: psmagin Date: Sun, 14 Jun 2026 09:59:15 +0300 Subject: [PATCH 01/16] init --- pom.xml | 2 +- .../packages/PackageByIdConverter.java | 8 ++-- .../PackageCollectionItemConverter.java | 16 +++---- .../converter/packages/PackageConverter.java | 33 +++++++------ .../resources/ResourceResultConverter.java | 12 ++--- .../rest/impl/EholdingsPackagesImpl.java | 47 ++++++++++++------- .../rest/impl/EholdingsProvidersImpl.java | 15 +++++- .../rest/impl/EholdingsResourcesImpl.java | 12 ++--- .../java/org/folio/rest/util/IdParser.java | 22 +++------ .../template/RmApiTemplateContextBuilder.java | 4 +- .../rest/validator/ResourcePostValidator.java | 4 +- .../org/folio/rmapi/PackageServiceImpl.java | 17 ++++--- .../org/folio/rmapi/ProvidersServiceImpl.java | 7 ++- .../org/folio/rmapi/ResourcesServiceImpl.java | 16 +++---- .../result/ObjectsForPostResourceResult.java | 4 +- .../org/folio/rmapi/result/PackageResult.java | 8 ++-- .../folio/rmapi/result/ResourceResult.java | 6 +-- .../loader/FilteredEntitiesLoaderImpl.java | 4 +- .../service/uc/UcCostPerUseServiceImpl.java | 8 ++-- .../spring/config/ApplicationConfig.java | 4 +- .../org/folio/rest/impl/WireMockTestBase.java | 4 +- .../EholdingsPackagesTest.java | 37 ++++++++------- .../org/folio/rest/util/IdParserTest.java | 6 +-- .../validator/ResourcePostValidatorTest.java | 14 +++--- .../java/org/folio/util/PackagesTestUtil.java | 10 ++-- .../rmapi/packages/get-packages-response.json | 10 ++-- 26 files changed, 173 insertions(+), 157 deletions(-) diff --git a/pom.xml b/pom.xml index f75824d66..37e302573 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.1 diff --git a/src/main/java/org/folio/rest/converter/packages/PackageByIdConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageByIdConverter.java index dc26d6bfc..fff4b0b4d 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageByIdConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageByIdConverter.java @@ -1,13 +1,13 @@ package org.folio.rest.converter.packages; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.rest.jaxrs.model.Package; import org.folio.rmapi.result.PackageResult; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @Component -public class PackageByIdConverter 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..27d62bb54 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java @@ -8,7 +8,6 @@ import org.folio.rest.jaxrs.model.Coverage; import org.folio.rest.jaxrs.model.PackageCollectionItem; import org.folio.rest.jaxrs.model.PackageDataAttributes; -import org.folio.rest.jaxrs.model.VisibilityData; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @@ -26,21 +25,22 @@ public PackageCollectionItem convert(PackageData packageData) { .withIsCustom(packageData.getIsCustom()) .withIsSelected(packageData.getIsSelected()) .withName(packageData.getPackageName()) - .withPackageId(packageData.getPackageId()) + .withPackageId(Math.toIntExact(packageData.getPackageId())) .withPackageType(packageData.getPackageType()) - .withProviderId(packageData.getVendorId()) + .withProviderId(Math.toIntExact(packageData.getVendorId())) .withProviderName(packageData.getVendorName()) .withSelectedCount(packageData.getSelectedCount()) .withTitleCount(packageData.getTitleCount()) .withAllowKbToAddTitles(packageData.getAllowEbscoToAddTitles()) - .withVisibilityData(convertVisibilityData(packageData))) +// .withVisibilityData(convertVisibilityData(packageData)) + ) .withRelationships(createEmptyPackageRelationship()); } - private VisibilityData convertVisibilityData(PackageData packageData) { - return new VisibilityData().withIsHidden(packageData.getVisibilityData().getIsHidden()) - .withReason(packageData.getVisibilityData().getReason().equals("Hidden by EP") ? "Set by system" : ""); - } +// private VisibilityData convertVisibilityData(PackageData packageData) { +// return new VisibilityData().withIsHidden(packageData.getVisibilityData().getIsHidden()) +// .withReason(packageData.getVisibilityData().getReason().equals("Hidden by EP") ? "Set by system" : ""); +// } private Coverage convertCustomCoverage(PackageData packageData) { return new Coverage() 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/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/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java index acfe81b7b..fe7228a36 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -30,11 +30,16 @@ 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.PackageFilter; +import org.folio.holdingsiq.model.PackageFilterSelected; +import org.folio.holdingsiq.model.PackageFilterType; 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.Pageable; +import org.folio.holdingsiq.model.SearchType; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; import org.folio.properties.common.SearchProperties; @@ -226,12 +231,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,14 +256,15 @@ 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(); @@ -338,7 +345,7 @@ private Function> retrievePackageTitl return context -> { var pkgId = filter.getPackageId(); return context.getTitlesService() - .retrieveTitles(pkgId.getProviderIdPart(), pkgId.getPackageIdPart(), filter.createFilterQuery(), + .retrieveTitles(pkgId.providerIdPart(), pkgId.packageIdPart(), filter.createFilterQuery(), searchProperties.titlesSearchType(), filter.getSort(), filter.getPage(), filter.getCount()) .thenApply(titles -> titleCollectionConverter.convert(titles)) .thenCompose(loadResourceTags(context)) @@ -346,10 +353,18 @@ private Function> retrievePackageTitl }; } - 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()); + private CompletableFuture retrievePackages(Long providerId, Filter filter, + RmApiTemplateContext context) { + var packageFilter = PackageFilter.builder() + .query(filter.getQuery()) + .filterSelected(PackageFilterSelected.fromValue(filter.getFilterSelected())) + .filterType(PackageFilterType.fromValue(filter.getFilterType())) + .searchType(SearchType.fromValue(searchProperties.packagesSearchType())) + .build(); + var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.getSort()); + return providerId == null + ? context.getPackagesService().retrievePackages(packageFilter, pageable) + : context.getPackagesService().retrievePackages(providerId, packageFilter, pageable); } @SuppressWarnings("java:S107") @@ -535,7 +550,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 +564,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 +580,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..66c596d41 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -22,7 +22,12 @@ import java.util.function.Function; import javax.ws.rs.core.Response; import org.folio.holdingsiq.model.OkapiData; +import org.folio.holdingsiq.model.PackageFilter; +import org.folio.holdingsiq.model.PackageFilterSelected; +import org.folio.holdingsiq.model.PackageFilterType; import org.folio.holdingsiq.model.Packages; +import org.folio.holdingsiq.model.Pageable; +import org.folio.holdingsiq.model.SearchType; import org.folio.holdingsiq.model.VendorById; import org.folio.holdingsiq.model.VendorPut; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; @@ -233,10 +238,16 @@ private Filter.FilterBuilder getPackageFilter(String providerId, String q, List< } private Function> retrieveFilteredPackages(Filter filter) { + var packageFilter = PackageFilter.builder() + .query(filter.getQuery()) + .filterSelected(PackageFilterSelected.fromValue(filter.getFilterSelected())) + .filterType(PackageFilterType.fromValue(filter.getFilterType())) + .searchType(SearchType.fromValue(packagesSearchType)) + .build(); + var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.getSort()); return context -> context.getPackagesService() - .retrievePackages(filter.getFilterSelected(), filter.getFilterType(), packagesSearchType, - filter.getProviderId(), filter.getQuery(), filter.getPage(), filter.getCount(), filter.getSort()) + .retrievePackages(filter.getProviderId(), packageFilter, pageable) .thenCompose(packages -> loadTags(packages, context)); } diff --git a/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java index bd9be22f8..b3d104823 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java @@ -36,7 +36,7 @@ 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.ResourceId; import org.folio.holdingsiq.model.ResourcePut; @@ -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( @@ -321,13 +317,13 @@ private CompletionStage getObjectsForPostResource( 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( diff --git a/src/main/java/org/folio/rest/util/IdParser.java b/src/main/java/org/folio/rest/util/IdParser.java index 3e76b2a38..e6d04be0f 100644 --- a/src/main/java/org/folio/rest/util/IdParser.java +++ b/src/main/java/org/folio/rest/util/IdParser.java @@ -28,15 +28,12 @@ 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(); + 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(); + return new PackageId(parts.get(0), parts.get(1)); } public static Long parseTitleId(String id) { @@ -48,11 +45,11 @@ public static Long parseProviderId(String id) { } 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) { 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..b82af90b3 100644 --- a/src/main/java/org/folio/rest/util/template/RmApiTemplateContextBuilder.java +++ b/src/main/java/org/folio/rest/util/template/RmApiTemplateContextBuilder.java @@ -4,7 +4,7 @@ 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.Title; import org.folio.holdingsiq.model.VendorById; import org.folio.holdingsiq.service.HoldingsIQService; @@ -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 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/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..5b9734928 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; @@ -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); } 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/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/loader/FilteredEntitiesLoaderImpl.java b/src/main/java/org/folio/service/loader/FilteredEntitiesLoaderImpl.java index e90b3783a..b100d1666 100644 --- a/src/main/java/org/folio/service/loader/FilteredEntitiesLoaderImpl.java +++ b/src/main/java/org/folio/service/loader/FilteredEntitiesLoaderImpl.java @@ -281,7 +281,7 @@ private List<Long> extractTitleIds(Collection<AccessTypeMapping> accessTypeMappi return accessTypeMappings.stream() .map(AccessTypeMapping::getRecordId) .map(IdParser::parseResourceId) - .map(ResourceId::getTitleIdPart) + .map(ResourceId::titleIdPart) .distinct() .collect(Collectors.toCollection(ArrayList::new)); } @@ -289,7 +289,7 @@ private List<Long> extractTitleIds(Collection<AccessTypeMapping> accessTypeMappi private List<Long> 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/uc/UcCostPerUseServiceImpl.java b/src/main/java/org/folio/service/uc/UcCostPerUseServiceImpl.java index 9ad9b511f..3bebc8e71 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)) @@ -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/spring/config/ApplicationConfig.java b/src/main/java/org/folio/spring/config/ApplicationConfig.java index 90342fe7c..ebd336391 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; @@ -121,7 +121,7 @@ public VertxCache<VendorIdCacheKey, Long> vendorIdCache(Vertx vertx, } @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"); diff --git a/src/test/java/org/folio/rest/impl/WireMockTestBase.java b/src/test/java/org/folio/rest/impl/WireMockTestBase.java index 48de280c1..78bfa1a30 100644 --- a/src/test/java/org/folio/rest/impl/WireMockTestBase.java +++ b/src/test/java/org/folio/rest/impl/WireMockTestBase.java @@ -35,7 +35,7 @@ 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.PackageData; import org.folio.holdingsiq.model.Title; import org.folio.holdingsiq.model.VendorById; import org.folio.okapi.common.XOkapiHeaders; @@ -77,7 +77,7 @@ public abstract class WireMockTestBase extends TestBase { @Qualifier("vendorIdCache") private VertxCache<VendorIdCacheKey, Long> vendorIdCache; @Autowired - private VertxCache<PackageCacheKey, PackageByIdData> packageCache; + private VertxCache<PackageCacheKey, PackageData> packageCache; @Autowired private VertxCache<VendorCacheKey, VendorById> vendorCache; @Autowired diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java index 498be798d..04036ac3f 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java @@ -97,7 +97,6 @@ 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; @@ -194,7 +193,7 @@ public void tearDown() { 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); + mockGet(new RegexPattern("/rm/rmaccounts/v2/" + STUB_CUSTOMER_ID + "/lists.*"), stubResponseFile); String packages = getWithOk(PACKAGES_ENDPOINT + "?q=American&filter[type]=abstractandindex&count=5", STUB_USER_ID_HEADER).asString(); @@ -546,8 +545,8 @@ public void shouldReturn400WhenPackageIsNotCustom() throws URISyntaxException, I 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(); + PackageData packageData = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageData.class); + packageData = packageData.toBuilder().isSelected(updatedIsSelected).build(); String updatedPackageValue = mapper.writeValueAsString(packageData); mockUpdateScenario(readFile(PACKAGE_STUB_FILE), updatedPackageValue); @@ -632,9 +631,9 @@ public void shouldDeleteAccessTypeMappingWhenRmApiSend404() throws URISyntaxExce 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() + PackageData packageData = mapper + .readValue(getFile(CUSTOM_PACKAGE_STUB_FILE), PackageData.class) + .toBuilder() .contentType("streamingmedia") .build(); @@ -683,8 +682,8 @@ public void shouldReturn422OnPutWhenCustomPackageUpdateLikeNotCustom() throws UR @Test public void shouldPassIsFullPackageAttributeToRmApi() throws URISyntaxException, IOException { - PackageByIdData updatedPackage = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageByIdData.class) - .toByIdBuilder().isSelected(true).build(); + PackageData updatedPackage = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageData.class) + .toBuilder().isSelected(true).build(); mockUpdateScenario(readFile(PACKAGE_STUB_FILE), mapper.writeValueAsString(updatedPackage)); @@ -1231,11 +1230,13 @@ public void shouldReturnEmptyPackagesOnFetchPackagesInBulkIfNoPackageIds() 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() + PackageData packageData = mapper.readValue(getFile(CUSTOM_PACKAGE_STUB_FILE), PackageData.class); + var visibilities = packageData.getVisibilityDetails().stream() + .map(visibilityDetail -> visibilityDetail.toBuilder().hidden(updatedHidden).build()) + .toList(); + packageData = packageData.toBuilder() .isSelected(updatedSelected) - .visibilityData(packageData.getVisibilityData().toBuilder().isHidden(updatedHidden).build()) + .visibilityDetails(visibilities) .customCoverage(CoverageDates.builder() .beginCoverage(updatedBeginCoverage) .endCoverage(updatedEndCoverage) @@ -1250,16 +1251,18 @@ private String prepareCustomPackageData(boolean updatedSelected, boolean updated 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() + PackageData packageData = mapper.readValue(getFile(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) - .visibilityData(packageData.getVisibilityData().toBuilder().isHidden(updatedHidden).build()) + .visibilityDetails(visibilities) .build(); return mapper.writeValueAsString(packageData); diff --git a/src/test/java/org/folio/rest/util/IdParserTest.java b/src/test/java/org/folio/rest/util/IdParserTest.java index 52a4cdd1f..b6a6b7965 100644 --- a/src/test/java/org/folio/rest/util/IdParserTest.java +++ b/src/test/java/org/folio/rest/util/IdParserTest.java @@ -11,9 +11,9 @@ public class IdParserTest { @Test public 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) diff --git a/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java b/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java index bd062a58d..417a25d55 100644 --- a/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java @@ -2,7 +2,7 @@ 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; @@ -56,7 +56,7 @@ public void shouldValidateTitleAndPackage() { @Test(expected = InputValidationException.class) public void shouldThrowExceptionWhenPackageIsNotCustom() { - PackageByIdData packageData = createPackage() + PackageData packageData = createPackage() .isCustom(false) .build(); validator.validateRelatedObjects( @@ -69,7 +69,7 @@ public void shouldThrowExceptionWhenPackageIsNotCustom() { public void shouldThrowExceptionWhenTitleIsAlreadyAddedToPackage() { Title title = createTitle().build(); Titles titles = createTitles().titleList(Collections.singletonList(title)).build(); - PackageByIdData packageData = createPackage().build(); + PackageData packageData = createPackage().build(); validator.validateRelatedObjects( packageData, title, @@ -92,11 +92,11 @@ 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) + .vendorId(123L) + .packageId(456L) .isCustom(true); } diff --git a/src/test/java/org/folio/util/PackagesTestUtil.java b/src/test/java/org/folio/util/PackagesTestUtil.java index e57ee674c..fd5c60bd7 100644 --- a/src/test/java/org/folio/util/PackagesTestUtil.java +++ b/src/test/java/org/folio/util/PackagesTestUtil.java @@ -34,7 +34,7 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.folio.holdingsiq.model.PackageByIdData; +import org.folio.holdingsiq.model.PackageData; import org.folio.repository.packages.DbPackage; import org.folio.rest.persist.PostgresClient; import org.folio.rest.util.IdParser; @@ -72,11 +72,11 @@ public static void savePackage(DbPackage dbPackage, Vertx vertx) { 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() + PackageData packageData = readJsonFile(STUB_PACKAGE_JSON_PATH, PackageData.class); + return Json.encode(packageData.toBuilder() .packageName(packageName) - .packageId(Integer.parseInt(packageId)) - .vendorId(Integer.parseInt(providerId)) + .packageId(Long.parseLong(packageId)) + .vendorId(Long.parseLong(providerId)) .build()); } 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..b6ba86df1 100644 --- a/src/test/resources/responses/rmapi/packages/get-packages-response.json +++ b/src/test/resources/responses/rmapi/packages/get-packages-response.json @@ -2,7 +2,7 @@ "totalResults": 414, "packagesList": [ { - "packageId": 3007, + "listId": 3007, "packageName": "American Academy of Family Physicians", "isCustom": false, "vendorId": 392, @@ -33,7 +33,7 @@ } }, { - "packageId": 1597443, + "listId": 1597443, "packageName": "American Academy of Orthopaedic Surgeons", "isCustom": false, "vendorId": 114569, @@ -54,7 +54,7 @@ "packageType": "Variable" }, { - "packageId": 3943, + "listId": 3943, "packageName": "American Academy of Pediatrics (AAP)", "isCustom": false, "vendorId": 554, @@ -75,7 +75,7 @@ "packageType": "Variable" }, { - "packageId": 7566, + "listId": 7566, "packageName": "American Academy of Pediatrics (AAP) eBooks", "isCustom": false, "vendorId": 554, @@ -96,7 +96,7 @@ "packageType": "Variable" }, { - "packageId": 19236, + "listId": 19236, "packageName": "American Academy of Pediatrics (KMLA)", "isCustom": false, "vendorId": 554, From 860b101ba156974f21dcf3a712a862c9f83bba30 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Wed, 17 Jun 2026 16:39:00 +0300 Subject: [PATCH 02/16] - test --- ramls/types/packages/packageAltName.json | 21 +++ .../types/packages/packageDataAttributes.json | 148 ++++++++++++------ .../packages/packagePutDataAttributes.json | 97 ++++++++---- ramls/types/packages/packageVisibility.json | 31 ++++ .../providers/ProviderRepository.java | 2 +- .../providers/ProviderRepositoryImpl.java | 9 +- ...ckageBulkFetchCollectionItemConverter.java | 4 +- .../PackageCollectionItemConverter.java | 65 +++++--- .../PackageCollectionResultConverter.java | 5 +- .../packages/PackageRequestConverter.java | 40 +++-- .../ResourceCollectionResultConverter.java | 13 +- .../rest/impl/EholdingsPackagesImpl.java | 28 ++-- .../rest/impl/EholdingsProvidersImpl.java | 22 ++- .../rest/impl/EholdingsResourcesImpl.java | 18 +-- .../folio/rest/impl/EholdingsStatusImpl.java | 14 +- .../folio/rest/impl/EholdingsTitlesImpl.java | 8 +- .../org/folio/rest/impl/LoadHoldingsImpl.java | 40 ++--- .../org/folio/rest/model/filter/Filter.java | 2 +- .../java/org/folio/rest/util/IdParser.java | 16 +- .../rest/util/template/RmApiTemplate.java | 6 +- .../util/template/RmApiTemplateContext.java | 4 +- .../template/RmApiTemplateContextBuilder.java | 14 +- .../validator/PackagePutBodyValidator.java | 5 +- .../rmapi/LocalConfigurationServiceImpl.java | 6 +- .../org/folio/rmapi/ProvidersServiceImpl.java | 8 +- .../org/folio/rmapi/TitlesServiceImpl.java | 10 +- .../service/holdings/HoldingsServiceImpl.java | 2 +- .../KbCredentialsServiceImpl.java | 18 +-- .../loader/FilteredEntitiesLoaderImpl.java | 16 +- .../loader/RelatedEntitiesLoaderImpl.java | 4 +- .../service/locale/LocaleSettingsService.java | 4 +- .../locale/LocaleSettingsServiceImpl.java | 16 +- .../service/uc/UcCostPerUseServiceImpl.java | 4 +- .../service/uc/export/ExportServiceImpl.java | 8 +- .../service/uc/export/TitleExportModel.java | 2 +- .../spring/config/ApplicationConfig.java | 2 +- .../providers/ProviderRepositoryImplTest.java | 3 +- .../packages/PackageRequestConverterTest.java | 37 +++-- .../org/folio/rest/impl/WireMockTestBase.java | 2 +- .../EholdingsPackagesTest.java | 12 +- .../PackagePutBodyValidatorTest.java | 13 +- .../validator/ResourcePostValidatorTest.java | 4 +- .../folio/rmapi/PackageServiceImplTest.java | 5 +- .../folio/rmapi/ResourceServiceImplTest.java | 6 +- .../export/LocaleSettingsServiceImplTest.java | 20 +-- .../java/org/folio/util/PackagesTestUtil.java | 4 +- .../rmapi/packages/put-package-custom.json | 6 + 47 files changed, 496 insertions(+), 328 deletions(-) create mode 100644 ramls/types/packages/packageAltName.json create mode 100644 ramls/types/packages/packageVisibility.json 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..23276bc8d 100644 --- a/ramls/types/packages/packageDataAttributes.json +++ b/ramls/types/packages/packageDataAttributes.json @@ -6,86 +6,142 @@ "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 - }, - "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" + "example": 1, + "type": "integer" }, - "proxy": { - "type": "object", - "description": "Proxy", - "$ref": "../proxy.json" + "url": { + "description": "Package URL", + "type": "string" }, - "tags": { - "type": "object", - "description": "Package tags", - "$ref": "../../raml-util/schemas/tags.schema" + "visibility": { + "description": "Visibility details", + "items": { + "$ref": "packageVisibility.json", + "type": "object" + }, + "type": "array" } } } diff --git a/ramls/types/packages/packagePutDataAttributes.json b/ramls/types/packages/packagePutDataAttributes.json index 1cc39ca20..78eaa942f 100644 --- a/ramls/types/packages/packagePutDataAttributes.json +++ b/ramls/types/packages/packagePutDataAttributes.json @@ -6,62 +6,91 @@ "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" } } } diff --git a/ramls/types/packages/packageVisibility.json b/ramls/types/packages/packageVisibility.json new file mode 100644 index 000000000..d2c0d167b --- /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", + "reason" + ] +} 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<Void> delete(String vendorId, UUID credentialsId, String tenantId); - CompletableFuture<List<Long>> findIdsByTagFilter(TagFilter tagFilter, UUID credentialsId, String tenantId); + CompletableFuture<List<Integer>> 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<Void> delete(String vendorId, UUID credentialsId, Strin } @Override - public CompletableFuture<List<Long>> findIdsByTagFilter(TagFilter tagFilter, UUID credentialsId, String tenantId) { + public CompletableFuture<List<Integer>> findIdsByTagFilter(TagFilter tagFilter, UUID credentialsId, String tenantId) { List<String> tags = tagFilter.getTags(); if (CollectionUtils.isEmpty(tags)) { return completedFuture(Collections.emptyList()); @@ -99,12 +100,12 @@ public CompletableFuture<List<Long>> findIdsByTagFilter(TagFilter tagFilter, UUI return mapResult(promise.future().recover(excTranslator.translateOrPassBy()), this::mapProviderIds); } - private List<Long> mapProviderIds(RowSet<Row> resultSet) { + private List<Integer> mapProviderIds(RowSet<Row> 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/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<Packag @Override public PackageBulkFetchCollectionItem convert(PackageData packageData) { - Integer providerId = packageData.getVendorId(); + var providerId = packageData.getVendorId(); String providerName = packageData.getVendorName(); - Integer packageId = packageData.getPackageId(); + var packageId = packageData.getPackageId(); return new PackageBulkFetchCollectionItem() .withId(providerId + "-" + packageId) 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 27d62bb54..149bb64f2 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.mapItems; 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.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @@ -19,32 +24,54 @@ 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(Math.toIntExact(packageData.getPackageId())) - .withPackageType(packageData.getPackageType()) - .withProviderId(Math.toIntExact(packageData.getVendorId())) - .withProviderName(packageData.getVendorName()) - .withSelectedCount(packageData.getSelectedCount()) - .withTitleCount(packageData.getTitleCount()) - .withAllowKbToAddTitles(packageData.getAllowEbscoToAddTitles()) -// .withVisibilityData(convertVisibilityData(packageData)) - ) + .withAttributes(convertAttributes(packageData)) .withRelationships(createEmptyPackageRelationship()); } -// private VisibilityData convertVisibilityData(PackageData packageData) { -// return new VisibilityData().withIsHidden(packageData.getVisibilityData().getIsHidden()) -// .withReason(packageData.getVisibilityData().getReason().equals("Hidden by EP") ? "Set by system" : ""); -// } + @SuppressWarnings("checkstyle:MethodLength") + private PackageDataAttributes convertAttributes(PackageData packageData) { + return new PackageDataAttributes() + .withAllowKbToAddTitles(packageData.getAllowEbscoToAddTitles()) + .withContentType(CONTENT_TYPES.get(packageData.getContentType().toLowerCase())) + .withCustomAltNames(mapItems(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(mapItems(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(mapItems(packageData.getVisibilityDetails(), this::convertVisibility)); + } + + 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) { return new Coverage() .withBeginCoverage(packageData.getCustomCoverage().getBeginCoverage()) .withEndCoverage(packageData.getCustomCoverage().getEndCoverage()); } + + private PackageAltName convertAltName(AlternateName alternateName) { + return new PackageAltName() + .withId(alternateName.id() == null ? null : Integer.parseInt(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<String> getTagsById(List<DbPackage> 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/PackageRequestConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java index 5d78b916e..e52a1dee3 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java @@ -1,10 +1,14 @@ 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 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.springframework.stereotype.Component; @@ -13,20 +17,20 @@ 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 +38,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 +55,27 @@ 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(null, packageAltName.getAltName()))); + } + + builder.customDescription(attributes.getCustomDescription()); + builder.customDisplayName(attributes.getCustomDisplayName()); + builder.packageFreeAccess(attributes.getIsFreeAccess()); + builder.packageUrl(attributes.getUrl()); + + builder.visibilityDetails(mapItems(attributes.getVisibility(), + pv -> new Visibility(pv.getCategory().value(), pv.getHidden(), pv.getReason()))); + 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<DbResource> 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/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java index fe7228a36..795b6246a 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -29,7 +29,6 @@ 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.PackageData; import org.folio.holdingsiq.model.PackageFilter; import org.folio.holdingsiq.model.PackageFilterSelected; @@ -39,6 +38,7 @@ import org.folio.holdingsiq.model.PackagePut; import org.folio.holdingsiq.model.Packages; import org.folio.holdingsiq.model.Pageable; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.SearchType; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; @@ -118,7 +118,7 @@ public class EholdingsPackagesImpl implements EholdingsPackages { private RmApiTemplateFactory templateFactory; @Autowired @Qualifier("vendorIdCache") - private VertxCache<VendorIdCacheKey, Long> vendorIdCache; + private VertxCache<VendorIdCacheKey, Integer> vendorIdCache; @Autowired private TagRepository tagRepository; @Autowired @@ -305,17 +305,17 @@ public void getEholdingsPackagesResourcesByPackageId(String packageId, List<Stri @Override public void putEholdingsPackagesTagsByPackageId(String packageId, String contentType, PackageTagsPutRequest entity, - Map<String, String> okapiHeaders, + Map<String, String> headers, Handler<AsyncResult<Response>> 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( @@ -353,7 +353,7 @@ private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitl }; } - private CompletableFuture<Packages> retrievePackages(Long providerId, Filter filter, + private CompletableFuture<Packages> retrievePackages(Integer providerId, Filter filter, RmApiTemplateContext context) { var packageFilter = PackageFilter.builder() .query(filter.getQuery()) @@ -412,7 +412,7 @@ private CompletableFuture<PackageResult> updateAccessTypeMapping(AccessType acce private CompletableFuture<Void> updateRecordMapping(AccessType accessType, String recordId, RmApiTemplateContext context) { return accessTypeMappingsService.update(accessType, recordId, RecordType.PACKAGE, context.getCredentialsId(), - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } private CompletableFuture<AccessType> fetchAccessType(PackagePutRequest entity, @@ -422,7 +422,7 @@ private CompletableFuture<AccessType> fetchAccessType(PackagePutRequest entity, return CompletableFuture.completedFuture(null); } else { return accessTypesService.findByCredentialsAndAccessTypeId(context.getCredentialsId(), accessTypeId, false, - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } } @@ -454,7 +454,7 @@ private Function<TitleCollectionResult, CompletionStage<TitleCollectionResult>> return titleCollection -> { Map<String, TitleResult> resourceIdToTitle = mapResourceIdToTitleResult(titleCollection); - return tagRepository.findPerRecord(context.getOkapiData().getTenant(), + return tagRepository.findPerRecord(context.getRequestContext().getTenant(), new ArrayList<>(resourceIdToTitle.keySet()), RecordType.RESOURCE) .thenApply(tagMap -> { @@ -476,7 +476,7 @@ private Function<TitleCollectionResult, CompletionStage<TitleCollectionResult>> return titleCollection -> { Map<String, TitleResult> 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 -> { @@ -505,12 +505,12 @@ private String getResourceId(TitleResult titleResult) { return resource.getVendorId() + "-" + resource.getPackageId() + "-" + resource.getTitleId(); } - private CompletableFuture<Long> getCustomProviderId(RmApiTemplateContext context) { + private CompletableFuture<Integer> 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 { @@ -524,7 +524,7 @@ private CompletableFuture<Long> getCustomProviderId(RmApiTemplateContext context private CompletableFuture<Void> 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)) diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index 66c596d41..9947ce730 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -21,12 +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.PackageFilter; import org.folio.holdingsiq.model.PackageFilterSelected; import org.folio.holdingsiq.model.PackageFilterType; import org.folio.holdingsiq.model.Packages; import org.folio.holdingsiq.model.Pageable; +import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.SearchType; import org.folio.holdingsiq.model.VendorById; import org.folio.holdingsiq.model.VendorPut; @@ -135,11 +135,10 @@ public void getEholdingsProviders(String q, List<String> filterTags, String sort public void getEholdingsProvidersByProviderId(String providerId, String include, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { - long providerIdLong = parseProviderId(providerId); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) .requestAction(context -> - context.getProvidersService().retrieveProvider(providerIdLong, include) + context.getProvidersService().retrieveProvider(parseProviderId(providerId), include) .thenCompose(result -> loadTags(result, context)) ) .addErrorMapper(ResourceNotFoundException.class, exception -> @@ -154,13 +153,12 @@ public void putEholdingsProvidersByProviderId(String providerId, String contentT Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> 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); @@ -169,18 +167,18 @@ public void putEholdingsProvidersByProviderId(String providerId, String contentT @Override public void putEholdingsProvidersTagsByProviderId(String providerId, String contentType, ProviderTagsPutRequest entity, - Map<String, String> okapiHeaders, + Map<String, String> headers, Handler<AsyncResult<Response>> 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) @@ -261,7 +259,7 @@ private CompletableFuture<VendorResult> loadTags(VendorResult result, RmApiTempl private CompletableFuture<PackageCollectionResult> 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)); } @@ -301,13 +299,13 @@ private CompletableFuture<Void> updateStoredProvider(DbProvider provider, Tags t return providerRepository.delete(provider.getId(), provider.getCredentialsId(), tenant); } - private CompletableFuture<VendorById> processUpdateRequest(ProviderPutRequest request, long providerIdLong, + private CompletableFuture<VendorById> 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 b3d104823..88bef6603 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java @@ -35,9 +35,9 @@ 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.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<String, @Override public void putEholdingsResourcesTagsByResourceId(String resourceId, String contentType, ResourceTagsPutRequest entity, - Map<String, String> okapiHeaders, + Map<String, String> headers, Handler<AsyncResult<Response>> 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<RmApiTemplateContext, CompletableFuture<?>> 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()) @@ -258,7 +258,7 @@ private CompletableFuture<AccessType> fetchAccessType(ResourcePutRequest entity, return CompletableFuture.completedFuture(null); } else { return accessTypesService.findByCredentialsAndAccessTypeId(context.getCredentialsId(), accessTypeId, false, - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } } @@ -276,7 +276,7 @@ private CompletableFuture<ResourceResult> updateAccessType(String recordId, Titl private CompletableFuture<Void> updateRecordMapping(AccessType accessType, String recordId, RmApiTemplateContext context) { return accessTypeMappingsService.update(accessType, recordId, RecordType.RESOURCE, context.getCredentialsId(), - context.getOkapiData().getHeaders()); + context.getRequestContext().getHeaders()); } private CompletableFuture<ResourceResult> loadRelatedEntities(ResourceResult result, RmApiTemplateContext context) { @@ -304,7 +304,7 @@ private CompletableFuture<Void> deleteAssignedResources(String resourceId, RmApi } private CompletableFuture<Void> 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) @@ -313,7 +313,7 @@ private CompletableFuture<Void> deleteTags(String resourceId, RmApiTemplateConte } private CompletionStage<ObjectsForPostResourceResult> getObjectsForPostResource( - Long titleId, PackageId packageId, + int titleId, PackageId packageId, TitlesHoldingsIQService titlesService, PackagesHoldingsIQService packagesService) { CompletableFuture<Title> titleFuture = titlesService.retrieveTitle(titleId); 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..3c40682b4 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java @@ -139,7 +139,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 +161,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) @@ -223,7 +223,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 +240,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/Filter.java b/src/main/java/org/folio/rest/model/filter/Filter.java index 42323773b..4f85f6395 100644 --- a/src/main/java/org/folio/rest/model/filter/Filter.java +++ b/src/main/java/org/folio/rest/model/filter/Filter.java @@ -129,7 +129,7 @@ public FilterQuery createFilterQuery() { .build(); } - public Long getProviderId() { + public Integer getProviderId() { return IdParser.parseProviderId(providerId); } diff --git a/src/main/java/org/folio/rest/util/IdParser.java b/src/main/java/org/folio/rest/util/IdParser.java index e6d04be0f..1bacef21f 100644 --- a/src/main/java/org/folio/rest/util/IdParser.java +++ b/src/main/java/org/folio/rest/util/IdParser.java @@ -27,20 +27,20 @@ private IdParser() { } public static ResourceId parseResourceId(String id) { - List<Long> parts = parseId(id, 3, RESOURCE_ID_INVALID_ERROR, RESOURCE_ID_INVALID_ERROR); + 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); + 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(); } @@ -93,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/template/RmApiTemplate.java b/src/main/java/org/folio/rest/util/template/RmApiTemplate.java index 593f1a74f..d923a2d0e 100644 --- a/src/main/java/org/folio/rest/util/template/RmApiTemplate.java +++ b/src/main/java/org/folio/rest/util/template/RmApiTemplate.java @@ -11,7 +11,7 @@ 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.holdingsiq.model.RequestContext; import org.folio.rest.util.ErrorHandler; import org.folio.rest.validator.HeaderValidator; import org.folio.service.kbcredentials.UserKbCredentialsService; @@ -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 b82af90b3..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.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 @@ -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..2160b3c92 100644 --- a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java +++ b/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java @@ -19,7 +19,8 @@ public void validate(PackagePutRequest request) { PackagePutDataAttributes attributes = request.getData().getAttributes(); Boolean allowKbToAddTitles = attributes.getAllowKbToAddTitles(); - Boolean isHidden = attributes.getVisibilityData() != null ? attributes.getVisibilityData().getIsHidden() : null; + // Boolean isHidden = attributes.getVisibilityData() != null + // ? attributes.getVisibilityData().getIsHidden() : null; String beginCoverage = null; String endCoverage = null; if (attributes.getCustomCoverage() != null) { @@ -29,7 +30,7 @@ public void validate(PackagePutRequest request) { String value = attributes.getPackageToken() != null ? attributes.getPackageToken().getValue() : null; - validateNotSelected(attributes, allowKbToAddTitles, isHidden, beginCoverage, endCoverage, value); + // validateNotSelected(attributes, allowKbToAddTitles, isHidden, beginCoverage, endCoverage, value); ValidatorUtil.checkMaxLength("value", value, MAX_TOKEN_LENGTH); ValidatorUtil.checkDateValid("beginCoverage", beginCoverage); ValidatorUtil.checkDateValid("endCoverage", endCoverage); 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/ProvidersServiceImpl.java b/src/main/java/org/folio/rmapi/ProvidersServiceImpl.java index 5b9734928..b0e001089 100644 --- a/src/main/java/org/folio/rmapi/ProvidersServiceImpl.java +++ b/src/main/java/org/folio/rmapi/ProvidersServiceImpl.java @@ -47,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; @@ -72,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()); @@ -90,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/TitlesServiceImpl.java b/src/main/java/org/folio/rmapi/TitlesServiceImpl.java index aed3533f9..b811e704e 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,7 +66,7 @@ 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)); } @@ -94,7 +94,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/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 b100d1666..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,7 +277,7 @@ 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) @@ -286,7 +286,7 @@ private List<Long> extractTitleIds(Collection<AccessTypeMapping> accessTypeMappi .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::titleIdPart) 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 3bebc8e71..2fa304202 100644 --- a/src/main/java/org/folio/service/uc/UcCostPerUseServiceImpl.java +++ b/src/main/java/org/folio/service/uc/UcCostPerUseServiceImpl.java @@ -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) 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/spring/config/ApplicationConfig.java b/src/main/java/org/folio/spring/config/ApplicationConfig.java index ebd336391..2fa213a01 100644 --- a/src/main/java/org/folio/spring/config/ApplicationConfig.java +++ b/src/main/java/org/folio/spring/config/ApplicationConfig.java @@ -115,7 +115,7 @@ 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"); } diff --git a/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java b/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java index 2d4c16994..bf44f529f 100644 --- a/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java +++ b/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java @@ -5,7 +5,6 @@ import static org.hamcrest.Matchers.empty; 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; @@ -27,7 +26,7 @@ public void shouldReturnEmptyListWhenTagListIsEmpty() { TagFilter filter = TagFilter.builder().tags(Collections.emptyList()) .recordType(RecordType.PROVIDER) .build(); - List<Long> providerIds = repository.findIdsByTagFilter(filter, null, STUB_TENANT).join(); + var providerIds = repository.findIdsByTagFilter(filter, null, STUB_TENANT).join(); assertThat(providerIds, empty()); } } 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..512700ec1 100644 --- a/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java +++ b/src/test/java/org/folio/rest/converter/packages/PackageRequestConverterTest.java @@ -8,7 +8,6 @@ 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.spring.config.TestConfig; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,15 +29,15 @@ public void shouldCreateRequestToSelectPackage() { assertTrue(packagePut.getIsSelected()); } - @Test - public void shouldCreateRequestToHidePackage() { - PackagePut packagePut = packagesConverter.convertToRmApiPackagePutRequest(PackagesTestData.getPackagePutRequest( - new PackagePutDataAttributes() - .withIsSelected(true) - .withVisibilityData(new VisibilityData() - .withIsHidden(true)))); - assertTrue(packagePut.getIsHidden()); - } + // @Test + // public void shouldCreateRequestToHidePackage() { + // PackagePut packagePut = packagesConverter.convertToRmApiPackagePutRequest(PackagesTestData.getPackagePutRequest( + // new PackagePutDataAttributes() + // .withIsSelected(true) + // .withVisibilityData(new VisibilityData() + // .withIsHidden(true)))); + // assertTrue(packagePut.getIsHidden()); + // } @Test public void shouldCreateRequestToAllowKbAddTitlesToPackage() { @@ -104,13 +103,13 @@ public void shouldCreateRequestToChangeCustomPackageContentType() { assertEquals(aggregatedFullTextContentTypeCode, packagePut.getContentType()); } - @Test - public void shouldCreateRequestToChangeCustomPackageVisibility() { - PackagePut packagePut = - packagesConverter.convertToRmApiCustomPackagePutRequest(PackagesTestData.getPackagePutRequest( - new PackagePutDataAttributes() - .withVisibilityData(new VisibilityData() - .withIsHidden(true)))); - assertTrue(packagePut.getIsHidden()); - } + // @Test + // public void shouldCreateRequestToChangeCustomPackageVisibility() { + // PackagePut packagePut = + // packagesConverter.convertToRmApiCustomPackagePutRequest(PackagesTestData.getPackagePutRequest( + // new PackagePutDataAttributes() + // .withVisibilityData(new VisibilityData() + // .withIsHidden(true)))); + // assertTrue(packagePut.getIsHidden()); + // } } diff --git a/src/test/java/org/folio/rest/impl/WireMockTestBase.java b/src/test/java/org/folio/rest/impl/WireMockTestBase.java index 78bfa1a30..4aed57ac9 100644 --- a/src/test/java/org/folio/rest/impl/WireMockTestBase.java +++ b/src/test/java/org/folio/rest/impl/WireMockTestBase.java @@ -75,7 +75,7 @@ public abstract class WireMockTestBase extends TestBase { private VertxCache<String, Configuration> configurationCache; @Autowired @Qualifier("vendorIdCache") - private VertxCache<VendorIdCacheKey, Long> vendorIdCache; + private VertxCache<VendorIdCacheKey, Integer> vendorIdCache; @Autowired private VertxCache<PackageCacheKey, PackageData> packageCache; @Autowired diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java index 04036ac3f..14195d622 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java @@ -579,7 +579,7 @@ public void shouldUpdateAllAttributesInSelectedPackage() throws URISyntaxExcepti assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); assertEquals(updatedAllowEbscoToAddTitles, actualPackage.getData().getAttributes().getAllowKbToAddTitles()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); + // assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); } @@ -610,7 +610,7 @@ public void shouldUpdateAllAttributesInSelectedPackageAndCreateNewAccessTypeMapp assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); assertEquals(updatedAllowEbscoToAddTitles, actualPackage.getData().getAttributes().getAllowKbToAddTitles()); - assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); + // assertEquals(updatedHidden, actualPackage.getData().getAttributes().getVisibilityData().getIsHidden()); assertEquals(updatedBeginCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getBeginCoverage()); assertEquals(updatedEndCoverage, actualPackage.getData().getAttributes().getCustomCoverage().getEndCoverage()); @@ -721,7 +721,7 @@ public void shouldUpdateAllAttributesInCustomPackage() throws URISyntaxException .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(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()); @@ -753,7 +753,7 @@ public void shouldUpdateAllAttributesInCustomPackageAndCreateNewAccessTypeMappin .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(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()); @@ -795,7 +795,7 @@ public void shouldUpdateAllAttributesInCustomPackageAndDeleteAccessTypeMapping() .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(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()); @@ -836,7 +836,7 @@ public void shouldUpdateAllAttributesInCustomPackageAndUpdateAccessTypeMapping() .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(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()); diff --git a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java index 886ef36c9..6808ae8eb 100644 --- a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java @@ -10,7 +10,6 @@ import org.folio.rest.jaxrs.model.Coverage; import org.folio.rest.jaxrs.model.PackagePutDataAttributes; import org.folio.rest.jaxrs.model.Token; -import org.folio.rest.jaxrs.model.VisibilityData; import org.junit.Test; public class PackagePutBodyValidatorTest { @@ -24,9 +23,10 @@ public void shouldValidateWhenPackageIsSelected() { .withIsSelected(true) .withCustomCoverage(new Coverage()) .withAllowKbToAddTitles(true) - .withVisibilityData(new VisibilityData() - .withIsHidden(false) - .withReason("")))); + // .withVisibilityData(new VisibilityData() + // .withIsHidden(false) + // .withReason("")) + )); } @Test @@ -34,8 +34,9 @@ public void shouldThrowExceptionWhenPackageIsNotSelectedAndIsHiddenIsTrue() { var request = PackagesTestData.getPackagePutRequest( new PackagePutDataAttributes() .withIsSelected(false) - .withVisibilityData(new VisibilityData() - .withIsHidden(true))); + // .withVisibilityData(new VisibilityData() + // .withIsHidden(true)) + ); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); assertThat(exception.getMessage(), containsString("isHidden")); diff --git a/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java b/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java index 417a25d55..7f34c26e5 100644 --- a/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java @@ -95,8 +95,8 @@ private ResourcePostRequest createRequest(String packageId, String titleId, Stri private PackageData.PackageDataBuilder createPackage() { return PackageData.builder() .packageName("package") - .vendorId(123L) - .packageId(456L) + .vendorId(123) + .packageId(456) .isCustom(true); } diff --git a/src/test/java/org/folio/rmapi/PackageServiceImplTest.java b/src/test/java/org/folio/rmapi/PackageServiceImplTest.java index 2db2a3790..223c684d0 100644 --- a/src/test/java/org/folio/rmapi/PackageServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/PackageServiceImplTest.java @@ -49,10 +49,7 @@ public void shouldReturnCachedPackage() throws IOException, URISyntaxException { mockGet(getPackagePattern, CUSTOM_PACKAGE_STUB_FILE); - PackageId packageId = PackageId.builder() - .packageIdPart(STUB_PACKAGE_ID) - .providerIdPart(STUB_VENDOR_ID) - .build(); + var packageId = new PackageId(STUB_PACKAGE_ID, STUB_VENDOR_ID); service.retrievePackage(packageId, Collections.emptyList(), true).join(); service.retrievePackage(packageId, Collections.emptyList(), true).join(); diff --git a/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java b/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java index d952205b1..28b1621c6 100644 --- a/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java @@ -50,11 +50,7 @@ public void shouldReturnCachedResource() throws IOException, URISyntaxException mockGet(getResourcePattern, 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(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_TITLE_ID); service.retrieveResource(resourceId, Collections.emptyList(), true).join(); service.retrieveResource(resourceId, Collections.emptyList(), true).join(); diff --git a/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java b/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java index 398d40055..b51233dbe 100644 --- a/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java +++ b/src/test/java/org/folio/service/export/LocaleSettingsServiceImplTest.java @@ -7,7 +7,7 @@ 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; @@ -24,7 +24,7 @@ public class LocaleSettingsServiceImplTest extends WireMockTestBase { @Autowired private LocaleSettingsService localeSettingsService; - private OkapiData okapiParams; + private RequestContext requestContext; @Override @Before @@ -34,7 +34,7 @@ public void setUp() throws Exception { headers.put(XOkapiHeaders.TOKEN, STUB_TOKEN); headers.put(XOkapiHeaders.TENANT, STUB_TENANT); headers.put(XOkapiHeaders.URL, getWiremockUrl()); - okapiParams = new OkapiData(headers); + requestContext = new RequestContext(headers); } @Test @@ -42,7 +42,7 @@ public void shouldReturnValidSettings(TestContext context) { var async = context.async(); mockSuccessfulLocaleResponse(); - var future = localeSettingsService.retrieveSettings(okapiParams); + var future = localeSettingsService.retrieveSettings(requestContext); future.thenCompose(result -> { context.assertEquals(result.getCurrency(), "EUR"); @@ -63,7 +63,7 @@ public void shouldReturnDefaultSettingsWhenResponseUnexpected(TestContext contex var configFileName = "responses/configuration/locale-unexpected.json"; mockSuccessfulLocaleResponse(configFileName); - var future = localeSettingsService.retrieveSettings(okapiParams); + var future = localeSettingsService.retrieveSettings(requestContext); future.thenCompose(result -> { assertLocaleSettingsRecoveredToDefault(context, result); @@ -80,7 +80,7 @@ public void shouldReturnDefaultSettingsWhenResponseUnexpected(TestContext contex public void shouldReturnDefaultSettingsWhenConfigurationFailed(TestContext context) { var async = context.async(); mockFailedLocaleResponse(); - var future = localeSettingsService.retrieveSettings(okapiParams); + var future = localeSettingsService.retrieveSettings(requestContext); future.thenCompose(result -> { assertLocaleSettingsRecoveredToDefault(context, result); @@ -97,7 +97,7 @@ public void shouldReturnDefaultSettingsWhenConfigurationFailed(TestContext conte public void shouldReturnDefaultSettingsWhenResponseIsInvalidJson(TestContext context) { var async = context.async(); mockLocaleResponseWithInvalidJson(); - var future = localeSettingsService.retrieveSettings(okapiParams); + var future = localeSettingsService.retrieveSettings(requestContext); future.thenCompose(result -> { assertLocaleSettingsRecoveredToDefault(context, result); @@ -114,7 +114,7 @@ public void shouldReturnDefaultSettingsWhenResponseIsInvalidJson(TestContext con public void shouldReturnDefaultSettingsWhenResponseIsEmpty(TestContext context) { var async = context.async(); mockLocaleResponseWithEmptyBody(); - var future = localeSettingsService.retrieveSettings(okapiParams); + var future = localeSettingsService.retrieveSettings(requestContext); future.thenCompose(result -> { assertLocaleSettingsRecoveredToDefault(context, result); @@ -131,7 +131,7 @@ public void shouldReturnDefaultSettingsWhenResponseIsEmpty(TestContext context) public void shouldReturnDefaultSettingsWhenServerError(TestContext context) { var async = context.async(); mockLocaleResponseWithServerError(); - var future = localeSettingsService.retrieveSettings(okapiParams); + var future = localeSettingsService.retrieveSettings(requestContext); future.thenCompose(result -> { assertLocaleSettingsRecoveredToDefault(context, result); @@ -148,7 +148,7 @@ public void shouldReturnDefaultSettingsWhenServerError(TestContext context) { public void shouldReturnDefaultSettingsWhenNetworkFailure(TestContext context) { var async = context.async(); mockLocaleResponseWithNetworkError(); - var future = localeSettingsService.retrieveSettings(okapiParams); + var future = localeSettingsService.retrieveSettings(requestContext); future.thenCompose(result -> { assertLocaleSettingsRecoveredToDefault(context, result); diff --git a/src/test/java/org/folio/util/PackagesTestUtil.java b/src/test/java/org/folio/util/PackagesTestUtil.java index fd5c60bd7..21e203c0f 100644 --- a/src/test/java/org/folio/util/PackagesTestUtil.java +++ b/src/test/java/org/folio/util/PackagesTestUtil.java @@ -75,8 +75,8 @@ public static String getPackageResponse(String packageName, String packageId, St PackageData packageData = readJsonFile(STUB_PACKAGE_JSON_PATH, PackageData.class); return Json.encode(packageData.toBuilder() .packageName(packageName) - .packageId(Long.parseLong(packageId)) - .vendorId(Long.parseLong(providerId)) + .packageId(Integer.parseInt(packageId)) + .vendorId(Integer.parseInt(providerId)) .build()); } 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..77c4a2901 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,17 @@ { "contentType": 8, "isSelected": true, + "customAltNames": [ + "Name of the ages (custom name)", + "Another custom name" + ], + "customDisplayName": "Name of The Ages (2026)", "customCoverage": { "beginCoverage": "2003-01-01", "endCoverage": "2004-01-01" }, "packageToken": null, "isHidden": true, + "isFreeAccess": true, "packageName": "name of the ages forever and ever" } From 3396063e102da03b3d734089021b0bf2f81e3cfc Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 19 Jun 2026 11:23:08 +0300 Subject: [PATCH 03/16] refactor: extract validation and factory logic from Filter class - Extract validation into FilterValidators with strategy pattern per RecordType (OCP) - Move TagFilter/AccessTypeFilter creation to static from() factory methods (SRP) - Consolidate duplicate validatePackageFilterType/validateTitleFilterType into single parameterized validateFilterType method (DRY) - Rename type-converting getters to explicit resolve*/parse* methods, letting Lombok generate raw-value getters for clean separation - Filter is now a focused data holder with only its own state accessors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../rest/impl/EholdingsPackagesImpl.java | 83 ++++++-- .../rest/impl/EholdingsProvidersImpl.java | 16 +- .../folio/rest/impl/EholdingsTitlesImpl.java | 8 +- .../rest/model/filter/AccessTypeFilter.java | 19 ++ .../org/folio/rest/model/filter/Filter.java | 194 +----------------- .../rest/model/filter/FilterValidator.java | 10 + .../rest/model/filter/FilterValidators.java | 163 +++++++++++++++ .../folio/rest/model/filter/TagFilter.java | 28 +++ 8 files changed, 307 insertions(+), 214 deletions(-) create mode 100644 src/main/java/org/folio/rest/model/filter/FilterValidator.java create mode 100644 src/main/java/org/folio/rest/model/filter/FilterValidators.java diff --git a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java index 795b6246a..9d793fb54 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -31,15 +31,19 @@ import org.folio.holdingsiq.model.CustomerResources; import org.folio.holdingsiq.model.PackageData; 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.PackageId; import org.folio.holdingsiq.model.PackagePost; import org.folio.holdingsiq.model.PackagePut; +import org.folio.holdingsiq.model.PackageSearchField; import org.folio.holdingsiq.model.Packages; import org.folio.holdingsiq.model.Pageable; import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.SearchType; +import org.folio.holdingsiq.model.Sort; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; import org.folio.properties.common.SearchProperties; @@ -69,7 +73,11 @@ 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.AccessTypeFilter; import org.folio.rest.model.filter.Filter; +import org.folio.rest.model.filter.PackageFilterParams; +import org.folio.rest.model.filter.TagFilter; +import org.folio.rest.model.query.PackageSearchParams; import org.folio.rest.util.ErrorHandler; import org.folio.rest.util.ErrorUtil; import org.folio.rest.util.template.RmApiTemplate; @@ -146,26 +154,29 @@ public EholdingsPackagesImpl() { @Override @Validate @HandleValidationErrors - public void getEholdingsPackages(String filterCustom, String q, String filterSelected, String filterType, - List<String> filterTags, List<String> filterAccessType, String sort, int page, - int count, - Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> 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 qField, String qType, boolean highlight, + String filterSelected, String filterType, String filterVisibility, + String filterFreeAccess, List<String> filterTags, List<String> filterAccessType, + String sort, int page, int count, Map<String, String> okapiHeaders, + Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { + var packageSearchParams = new PackageSearchParams(q, qField, qType, highlight); + var packageFilterParams = new PackageFilterParams(filterCustom, filterSelected, filterType, filterVisibility, + filterFreeAccess, filterTags, filterAccessType); + var pageable = new Pageable(page, count, Sort.valueOf(sort.toUpperCase())); + + var filter = Filter.getPackageFilter(packageSearchParams, packageFilterParams, pageable); 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 { @@ -289,10 +300,10 @@ public void getEholdingsPackagesResourcesByPackageId(String packageId, List<Stri 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)); } @@ -343,10 +354,10 @@ public void postEholdingsPackagesBulkFetch(String contentType, PackagePostBulkFe private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitles(Filter filter) { return context -> { - var pkgId = filter.getPackageId(); + var pkgId = filter.parsePackageId(); return context.getTitlesService() .retrieveTitles(pkgId.providerIdPart(), pkgId.packageIdPart(), filter.createFilterQuery(), - searchProperties.titlesSearchType(), filter.getSort(), filter.getPage(), filter.getCount()) + searchProperties.titlesSearchType(), filter.resolveSort(), filter.getPage(), filter.getCount()) .thenApply(titles -> titleCollectionConverter.convert(titles)) .thenCompose(loadResourceTags(context)) .thenCompose(loadResourceAccessTypes(context)); @@ -355,18 +366,48 @@ private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitl private CompletableFuture<Packages> retrievePackages(Integer providerId, Filter filter, RmApiTemplateContext context) { + var filterParams = filter.getPackageFilterParams(); + var searchParams = filter.getPackageSearchParams(); var packageFilter = PackageFilter.builder() - .query(filter.getQuery()) - .filterSelected(PackageFilterSelected.fromValue(filter.getFilterSelected())) - .filterType(PackageFilterType.fromValue(filter.getFilterType())) - .searchType(SearchType.fromValue(searchProperties.packagesSearchType())) + .query(searchParams.query()) + .searchType(searchParams.queryType() == null + ? SearchType.fromValue(searchProperties.packagesSearchType()) + : SearchType.fromValue(searchParams.queryType())) + .searchField(PackageSearchField.fromValue(searchParams.queryField())) + .highlightTag(searchParams.highlight() ? searchProperties.highlightTag() : null) + .filterSelected(PackageFilterSelected.fromValue(filterParams.filterSelected())) + .filterType(PackageFilterType.fromValue(filterParams.filterType())) + .filterPackageFreeAccess(toFilterPackageFreeAccess(filterParams.filterFreeAccess())) + .filterVisibility(toFilterVisibility(filterParams.filterVisibility())) .build(); - var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.getSort()); + var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.resolveSort()); return providerId == null ? context.getPackagesService().retrievePackages(packageFilter, pageable) : context.getPackagesService().retrievePackages(providerId, packageFilter, pageable); } + private PackageFilterVisibility toFilterVisibility(String source) { + return switch (source) { + case "visibleInPF" -> PackageFilterVisibility.VISIBLE_IN_PF; + case "visibleInFTF" -> PackageFilterVisibility.VISIBLE_IN_FTF; + case "visibleInMARC" -> PackageFilterVisibility.INCLUDED_IN_MARC; + case "hiddenInPF" -> PackageFilterVisibility.HIDDEN_IN_PF; + case "hiddenInFTF" -> PackageFilterVisibility.HIDDEN_IN_FTF; + case "hiddenInMARC" -> PackageFilterVisibility.EXCLUDED_FROM_MARC; + case null -> null; + default -> throw new IllegalStateException("Unexpected value: " + source); + }; + } + + private PackageFilterFreeAccess toFilterPackageFreeAccess(String source) { + return switch (source) { + case "public" -> PackageFilterFreeAccess.TRUE; + case "controlled" -> PackageFilterFreeAccess.FALSE; + case null -> null; + default -> throw new IllegalStateException("Unexpected value: " + source); + }; + } + @SuppressWarnings("java:S107") private Filter.FilterBuilder prepareFilterForResource(String packageId, List<String> filterTags, List<String> filterAccessType, String filterSelected, @@ -419,7 +460,7 @@ private CompletableFuture<AccessType> 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.getRequestContext().getHeaders()); diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index 9947ce730..27b888820 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -51,7 +51,9 @@ 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.AccessTypeFilter; import org.folio.rest.model.filter.Filter; +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; @@ -121,11 +123,11 @@ public void getEholdingsProviders(String q, List<String> 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); } @@ -207,10 +209,10 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String 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)); @@ -238,14 +240,14 @@ private Filter.FilterBuilder getPackageFilter(String providerId, String q, List< private Function<RmApiTemplateContext, CompletableFuture<?>> retrieveFilteredPackages(Filter filter) { var packageFilter = PackageFilter.builder() .query(filter.getQuery()) - .filterSelected(PackageFilterSelected.fromValue(filter.getFilterSelected())) + .filterSelected(PackageFilterSelected.fromValue(filter.resolveFilterSelected())) .filterType(PackageFilterType.fromValue(filter.getFilterType())) .searchType(SearchType.fromValue(packagesSearchType)) .build(); - var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.getSort()); + var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.resolveSort()); return context -> context.getPackagesService() - .retrievePackages(filter.getProviderId(), packageFilter, pageable) + .retrievePackages(filter.parseProviderId(), packageFilter, pageable) .thenCompose(packages -> loadTags(packages, context)); } diff --git a/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java index 3c40682b4..4d4465589 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.AccessTypeFilter; import org.folio.rest.model.filter.Filter; +import org.folio.rest.model.filter.TagFilter; import org.folio.rest.util.ErrorUtil; import org.folio.rest.util.IdParser; import org.folio.rest.util.template.RmApiTemplateContext; @@ -184,13 +186,13 @@ public void putEholdingsTitlesByTitleId(String titleId, String contentType, Titl private CompletableFuture<Titles> fetchTitlesByFilter(Filter 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() ); } } 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..8f829c07d 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,23 @@ 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()); + + RecordType recordType = filter.getRecordType(); + if (recordType == RecordType.PACKAGE) { + accessTypeFilter.setRecordIdPrefix(filter.getProviderId()); + accessTypeFilter.setRecordType(RecordType.PACKAGE); + } else if (recordType == RecordType.RESOURCE) { + accessTypeFilter.setRecordIdPrefix(filter.getPackageId()); + accessTypeFilter.setRecordType(RecordType.RESOURCE); + } else if (recordType == RecordType.TITLE) { + accessTypeFilter.setRecordType(RecordType.RESOURCE); + } + 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 4f85f6395..292026475 100644 --- a/src/main/java/org/folio/rest/model/filter/Filter.java +++ b/src/main/java/org/folio/rest/model/filter/Filter.java @@ -1,25 +1,15 @@ 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.Sort; @@ -57,8 +47,9 @@ public static FilterBuilder builder() { @Override public Filter build() { - validate(); - return super.build(); + Filter filter = super.build(); + FilterValidators.validate(filter); + return filter; } }; } @@ -79,44 +70,6 @@ public boolean isAccessTypeFilter() { return isCheckedFilter(filterAccessType, filterTags); } - 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(); - } - public FilterQuery createFilterQuery() { return FilterQuery.builder() .type(filterType) @@ -124,41 +77,37 @@ public FilterQuery createFilterQuery() { .isxn(filterIsxn) .subject(filterSubject) .publisher(filterPublisher) - .selected(getFilterSelected()) - .packageIds(getFilterPackageIds()) + .selected(resolveFilterSelected()) + .packageIds(resolveFilterPackageIds()) .build(); } - public Integer getProviderId() { + public Integer parseProviderId() { return IdParser.parseProviderId(providerId); } - public PackageId getPackageId() { + public PackageId parsePackageId() { return IdParser.parsePackageId(packageId); } - public String getFilterSelected() { + public String resolveFilterSelected() { return filterSelected == null ? null : FILTER_SELECTED_MAPPING.get(filterSelected); } - public List<Integer> getFilterPackageIds() { + public List<Integer> resolveFilterPackageIds() { return filterPackageIds == null ? null : filterPackageIds.stream() .map(Integer::parseInt) .toList(); } - public Boolean getFilterCustom() { + public Boolean resolveFilterCustom() { return filterCustom == null ? null : Boolean.parseBoolean(filterCustom); } - public Sort getSort() { + public Sort resolveSort() { 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) @@ -167,125 +116,4 @@ && 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); - } - } - } } 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..ec26bd015 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/FilterValidator.java @@ -0,0 +1,10 @@ +package org.folio.rest.model.filter; + +/** + * Strategy interface for record-type-specific filter validation. + */ +@FunctionalInterface +public interface FilterValidator { + + void validate(Filter filter); +} 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..7299474f0 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/FilterValidators.java @@ -0,0 +1,163 @@ +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.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.folio.holdingsiq.model.Sort; +import org.folio.repository.RecordType; +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_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 static final Map<RecordType, FilterValidator> VALIDATORS = new EnumMap<>(RecordType.class); + + static { + VALIDATORS.put(RecordType.PROVIDER, FilterValidators::validateProvider); + VALIDATORS.put(RecordType.PACKAGE, FilterValidators::validatePackage); + VALIDATORS.put(RecordType.RESOURCE, FilterValidators::validateResource); + VALIDATORS.put(RecordType.TITLE, FilterValidators::validateTitle); + } + + private FilterValidators() { + } + + public static void validate(Filter filter) { + if (CollectionUtils.isNotEmpty(filter.getFilterTags()) + || CollectionUtils.isNotEmpty(filter.getFilterAccessType())) { + return; + } + + validateSort(filter); + + FilterValidator validator = VALIDATORS.get(filter.getRecordType()); + if (validator != null) { + validator.validate(filter); + } + } + + private static void validateProvider(Filter filter) { + validateQuery(filter); + } + + private static void validatePackage(Filter filter) { + validateQuery(filter); + validateFilterType(filter, SUPPORTED_PACKAGE_FILTER_TYPE_VALUES); + validateFilterCustom(filter); + validateFilterSelected(filter); + validateProviderId(filter); + } + + private static void validateResource(Filter filter) { + validatePackageId(filter); + validateFilterType(filter, SUPPORTED_TITLE_FILTER_TYPE_VALUES); + validateFilterSelected(filter); + validateKeywordSearch(filter, true); + } + + private static void validateTitle(Filter filter) { + validateFilterType(filter, SUPPORTED_TITLE_FILTER_TYPE_VALUES); + validateFilterSelected(filter); + validateFilterPackageIds(filter); + validateKeywordSearch(filter, false); + } + + private static void validateSort(Filter filter) { + if (!Sort.contains(filter.getSort().toUpperCase())) { + throw new ValidationException(INVALID_SORT_PARAMETER_MESSAGE); + } + } + + private static void validateQuery(Filter filter) { + if ("".equals(filter.getQuery())) { + throw new ValidationException(INVALID_QUERY_PARAMETER_MESSAGE); + } + } + + private static void validateFilterType(Filter filter, Collection<String> supportedValues) { + if (filter.getFilterType() != null && !supportedValues.contains(filter.getFilterType())) { + throw new ValidationException(INVALID_FILTER_TYPE_PARAMETER_MESSAGE); + } + } + + private static void validateFilterCustom(Filter filter) { + if (filter.getFilterCustom() != null && !Boolean.parseBoolean(filter.getFilterCustom())) { + throw new ValidationException(INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE); + } + } + + private static void validateFilterSelected(Filter filter) { + if (filter.getFilterSelected() != null + && !FILTER_SELECTED_MAPPING.containsKey(filter.getFilterSelected())) { + throw new ValidationException(INVALID_FILTER_SELECTED_PARAMETER_MESSAGE); + } + } + + private static void validateFilterPackageIds(Filter filter) { + List<String> packageIds = filter.getFilterPackageIds(); + if (packageIds != null && !packageIds.isEmpty()) { + packageIds.forEach(id -> { + if (!isNumeric(id)) { + throw new ValidationException(INVALID_FILTER_PACKAGE_IDS_PARAMETER_MESSAGE); + } + }); + } + } + + private static void validateKeywordSearch(Filter filter, boolean allowNullFilters) { + List<String> searchParameters = + asList(filter.getFilterName(), filter.getFilterIsxn(), + filter.getFilterSubject(), filter.getFilterPublisher()); + + 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(Filter filter) { + if (filter.getProviderId() != null) { + IdParser.parseProviderId(filter.getProviderId()); + } + } + + private static void validatePackageId(Filter filter) { + if (filter.getPackageId() != null) { + IdParser.parsePackageId(filter.getPackageId()); + } + } +} 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..b9b701c82 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,29 @@ public class TagFilter { RecordType recordType; int offset; int count; + + public static TagFilter from(Filter filter) { + RecordType recordType = filter.getRecordType(); + TagFilterBuilder builder = TagFilter.builder() + .tags(filter.getFilterTags()) + .recordType(recordType) + .offset((filter.getPage() - 1) * filter.getCount()) + .count(filter.getCount()); + + switch (recordType) { + case PACKAGE -> builder.recordIdPrefix(ensureTrailingDash(filter.getProviderId())); + case RESOURCE -> builder.recordIdPrefix(ensureTrailingDash(filter.getPackageId())); + case TITLE -> { + builder.recordType(RecordType.RESOURCE); + builder.recordIdPrefix(""); + } + case null, default -> builder.recordIdPrefix(""); + } + + return builder.build(); + } + + private static String ensureTrailingDash(String id) { + return isBlank(id) ? "" : Strings.CS.appendIfMissing(id, "-"); + } } From f030f003a21090605df20048337d0efac36ca436 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 19 Jun 2026 11:42:22 +0300 Subject: [PATCH 04/16] refactor: split Filter into sealed interface with per-type implementations - Filter is now a sealed interface with ProviderFilter, PackageRecordFilter, ResourceFilter, and TitleFilter implementations - Each type carries only its relevant fields (ISP compliance) - Validation is self-contained per type via FilterValidators - TagFilter.from() and AccessTypeFilter.from() use pattern matching on sealed types instead of RecordType switches - Removed dead code: prepareFilterForPackage(), prepareFilterForResource(), getSortableFilter(), getPackageFilter() helper methods - Removed FilterValidator strategy interface (no longer needed) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../rest/impl/EholdingsPackagesImpl.java | 56 +++----- .../rest/impl/EholdingsProvidersImpl.java | 34 +++-- .../folio/rest/impl/EholdingsTitlesImpl.java | 7 +- .../rest/model/filter/AccessTypeFilter.java | 20 +-- .../org/folio/rest/model/filter/Filter.java | 113 ++++------------- .../rest/model/filter/FilterValidator.java | 10 -- .../rest/model/filter/FilterValidators.java | 120 +++++++++--------- .../model/filter/PackageRecordFilter.java | 80 ++++++++++++ .../rest/model/filter/ProviderFilter.java | 41 ++++++ .../rest/model/filter/ResourceFilter.java | 69 ++++++++++ .../folio/rest/model/filter/TagFilter.java | 13 +- .../folio/rest/model/filter/TitleFilter.java | 70 ++++++++++ 12 files changed, 396 insertions(+), 237 deletions(-) delete mode 100644 src/main/java/org/folio/rest/model/filter/FilterValidator.java create mode 100644 src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java create mode 100644 src/main/java/org/folio/rest/model/filter/ProviderFilter.java create mode 100644 src/main/java/org/folio/rest/model/filter/ResourceFilter.java create mode 100644 src/main/java/org/folio/rest/model/filter/TitleFilter.java diff --git a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java index 9d793fb54..23ee6cd64 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -74,8 +74,9 @@ import org.folio.rest.jaxrs.model.Tags; import org.folio.rest.jaxrs.resource.EholdingsPackages; import org.folio.rest.model.filter.AccessTypeFilter; -import org.folio.rest.model.filter.Filter; import org.folio.rest.model.filter.PackageFilterParams; +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.model.query.PackageSearchParams; import org.folio.rest.util.ErrorHandler; @@ -164,7 +165,7 @@ public void getEholdingsPackages(String filterCustom, String q, String qField, S filterFreeAccess, filterTags, filterAccessType); var pageable = new Pageable(page, count, Sort.valueOf(sort.toUpperCase())); - var filter = Filter.getPackageFilter(packageSearchParams, packageFilterParams, pageable); + var filter = PackageRecordFilter.create(packageSearchParams, packageFilterParams, pageable); var template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); if (filter.isTagsFilter()) { @@ -293,8 +294,20 @@ public void getEholdingsPackagesResourcesByPackageId(String packageId, List<Stri Handler<AsyncResult<Response>> 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); @@ -352,7 +365,7 @@ public void postEholdingsPackagesBulkFetch(String contentType, PackagePostBulkFe .executeWithResult(PackageBulkFetchCollection.class); } - private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitles(Filter filter) { + private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitles(ResourceFilter filter) { return context -> { var pkgId = filter.parsePackageId(); return context.getTitlesService() @@ -364,7 +377,7 @@ private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitl }; } - private CompletableFuture<Packages> retrievePackages(Integer providerId, Filter filter, + private CompletableFuture<Packages> retrievePackages(Integer providerId, PackageRecordFilter filter, RmApiTemplateContext context) { var filterParams = filter.getPackageFilterParams(); var searchParams = filter.getPackageSearchParams(); @@ -408,37 +421,6 @@ private PackageFilterFreeAccess toFilterPackageFreeAccess(String source) { }; } - @SuppressWarnings("java:S107") - private Filter.FilterBuilder prepareFilterForResource(String packageId, List<String> filterTags, - List<String> 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<String> filterTags, - List<String> filterAccessType) { - return Filter.builder() - .recordType(RecordType.PACKAGE) - .query(q) - .filterTags(filterTags) - .filterCustom(filterCustom) - .filterAccessType(filterAccessType) - .filterSelected(filterSelected) - .filterType(filterType); - } - private CompletableFuture<PackageResult> updateAccessTypeMapping(AccessType accessType, PackageResult packageResult, RmApiTemplateContext context) { diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index 27b888820..3b51c5195 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -52,7 +52,8 @@ import org.folio.rest.jaxrs.model.Tags; import org.folio.rest.jaxrs.resource.EholdingsProviders; import org.folio.rest.model.filter.AccessTypeFilter; -import org.folio.rest.model.filter.Filter; +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; @@ -113,8 +114,7 @@ public void getEholdingsProviders(String q, List<String> filterTags, String sort Handler<AsyncResult<Response>> 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) @@ -203,8 +203,17 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { - var filter = Filter.getSortableFilter(getPackageFilter(providerId, q, filterTags, filterAccessType, filterSelected, - filterType), sort, page, count); + var filter = PackageRecordFilter.builder() + .query(q) + .filterTags(filterTags) + .providerId(providerId) + .filterAccessType(filterAccessType) + .filterSelected(filterSelected) + .filterType(filterType) + .sort(sort) + .page(page) + .count(count) + .build(); RmApiTemplate template = templateFactory.createTemplate(okapiHeaders, asyncResultHandler); if (filter.isTagsFilter()) { @@ -224,20 +233,7 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String .executeWithResult(PackageCollection.class); } - private Filter.FilterBuilder getPackageFilter(String providerId, String q, List<String> filterTags, - List<String> 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<RmApiTemplateContext, CompletableFuture<?>> retrieveFilteredPackages(Filter filter) { + private Function<RmApiTemplateContext, CompletableFuture<?>> retrieveFilteredPackages(PackageRecordFilter filter) { var packageFilter = PackageFilter.builder() .query(filter.getQuery()) .filterSelected(PackageFilterSelected.fromValue(filter.resolveFilterSelected())) diff --git a/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java index 4d4465589..e7e7a303f 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsTitlesImpl.java @@ -40,8 +40,8 @@ import org.folio.rest.jaxrs.model.TitlePutRequest; import org.folio.rest.jaxrs.resource.EholdingsTitles; import org.folio.rest.model.filter.AccessTypeFilter; -import org.folio.rest.model.filter.Filter; 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; @@ -96,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) @@ -184,7 +183,7 @@ 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(TagFilter.from(filter), context); } else if (filter.isAccessTypeFilter()) { 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 8f829c07d..ffc58be05 100644 --- a/src/main/java/org/folio/rest/model/filter/AccessTypeFilter.java +++ b/src/main/java/org/folio/rest/model/filter/AccessTypeFilter.java @@ -21,15 +21,17 @@ public static AccessTypeFilter from(Filter filter) { accessTypeFilter.setCount(filter.getCount()); accessTypeFilter.setPage(filter.getPage()); - RecordType recordType = filter.getRecordType(); - if (recordType == RecordType.PACKAGE) { - accessTypeFilter.setRecordIdPrefix(filter.getProviderId()); - accessTypeFilter.setRecordType(RecordType.PACKAGE); - } else if (recordType == RecordType.RESOURCE) { - accessTypeFilter.setRecordIdPrefix(filter.getPackageId()); - accessTypeFilter.setRecordType(RecordType.RESOURCE); - } else if (recordType == RecordType.TITLE) { - accessTypeFilter.setRecordType(RecordType.RESOURCE); + 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 292026475..2c9b5ea51 100644 --- a/src/main/java/org/folio/rest/model/filter/Filter.java +++ b/src/main/java/org/folio/rest/model/filter/Filter.java @@ -1,119 +1,56 @@ package org.folio.rest.model.filter; -import static java.util.Arrays.asList; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; import static org.apache.commons.collections4.IterableUtils.matchesAll; import static org.folio.rest.util.RestConstants.FILTER_SELECTED_MAPPING; import java.util.List; -import lombok.Builder; -import lombok.Value; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.folio.holdingsiq.model.FilterQuery; -import org.folio.holdingsiq.model.PackageId; 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; + // Common getters (implemented by each @Value class via Lombok) + 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() { - Filter filter = super.build(); - FilterValidators.validate(filter); - return filter; - } - }; - } - - public static Filter getSortableFilter(Filter.FilterBuilder filterBuilder, String sort, int page, int count) { - return filterBuilder - .sort(sort) - .page(page) - .count(count) - .build(); - } + // Each impl returns its own search-criteria field values (used by isTagsFilter/isAccessTypeFilter) + List<String> searchCriteriaValues(); - public boolean isTagsFilter() { - return isCheckedFilter(filterTags, filterAccessType); + // Default methods + default Sort resolveSort() { + return Sort.valueOf(getSort().toUpperCase()); } - public boolean isAccessTypeFilter() { - return isCheckedFilter(filterAccessType, filterTags); + default boolean isTagsFilter() { + return isFilteredBy(getFilterTags(), getFilterAccessType()); } - public FilterQuery createFilterQuery() { - return FilterQuery.builder() - .type(filterType) - .name(filterName) - .isxn(filterIsxn) - .subject(filterSubject) - .publisher(filterPublisher) - .selected(resolveFilterSelected()) - .packageIds(resolveFilterPackageIds()) - .build(); + default boolean isAccessTypeFilter() { + return isFilteredBy(getFilterAccessType(), getFilterTags()); } - public Integer parseProviderId() { - return IdParser.parseProviderId(providerId); + // 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 PackageId parsePackageId() { - return IdParser.parsePackageId(packageId); - } - - public String resolveFilterSelected() { + // Shared utility for resolveFilterSelected (used by 3 implementations) + static String mapFilterSelected(String filterSelected) { return filterSelected == null ? null : FILTER_SELECTED_MAPPING.get(filterSelected); } - - public List<Integer> resolveFilterPackageIds() { - return filterPackageIds == null ? null : filterPackageIds.stream() - .map(Integer::parseInt) - .toList(); - } - - public Boolean resolveFilterCustom() { - return filterCustom == null ? null : Boolean.parseBoolean(filterCustom); - } - - public Sort resolveSort() { - return Sort.valueOf(sort.toUpperCase()); - } - - 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); - } } diff --git a/src/main/java/org/folio/rest/model/filter/FilterValidator.java b/src/main/java/org/folio/rest/model/filter/FilterValidator.java deleted file mode 100644 index ec26bd015..000000000 --- a/src/main/java/org/folio/rest/model/filter/FilterValidator.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.folio.rest.model.filter; - -/** - * Strategy interface for record-type-specific filter validation. - */ -@FunctionalInterface -public interface FilterValidator { - - void validate(Filter filter); -} diff --git a/src/main/java/org/folio/rest/model/filter/FilterValidators.java b/src/main/java/org/folio/rest/model/filter/FilterValidators.java index 7299474f0..8a0dd5df8 100644 --- a/src/main/java/org/folio/rest/model/filter/FilterValidators.java +++ b/src/main/java/org/folio/rest/model/filter/FilterValidators.java @@ -10,14 +10,11 @@ import jakarta.validation.ValidationException; import java.util.Collection; -import java.util.EnumMap; import java.util.List; -import java.util.Map; import java.util.Objects; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.folio.holdingsiq.model.Sort; -import org.folio.repository.RecordType; import org.folio.rest.util.IdParser; public final class FilterValidators { @@ -37,91 +34,88 @@ public final class FilterValidators { static final String INVALID_KEYWORD_SEARCH_PARAMETERS_MESSAGE = "Value of required parameter filter[name], filter[isxn], filter[subject] or filter[publisher] is missing."; - private static final Map<RecordType, FilterValidator> VALIDATORS = new EnumMap<>(RecordType.class); - - static { - VALIDATORS.put(RecordType.PROVIDER, FilterValidators::validateProvider); - VALIDATORS.put(RecordType.PACKAGE, FilterValidators::validatePackage); - VALIDATORS.put(RecordType.RESOURCE, FilterValidators::validateResource); - VALIDATORS.put(RecordType.TITLE, FilterValidators::validateTitle); - } - private FilterValidators() { } - public static void validate(Filter filter) { + public static void validateProvider(ProviderFilter filter) { if (CollectionUtils.isNotEmpty(filter.getFilterTags()) || CollectionUtils.isNotEmpty(filter.getFilterAccessType())) { return; } - - validateSort(filter); - - FilterValidator validator = VALIDATORS.get(filter.getRecordType()); - if (validator != null) { - validator.validate(filter); - } - } - - private static void validateProvider(Filter filter) { - validateQuery(filter); + validateSort(filter.getSort()); + validateQuery(filter.getQuery()); } - private static void validatePackage(Filter filter) { - validateQuery(filter); - validateFilterType(filter, SUPPORTED_PACKAGE_FILTER_TYPE_VALUES); - validateFilterCustom(filter); - validateFilterSelected(filter); - validateProviderId(filter); + public static void validatePackage(PackageRecordFilter filter) { + if (CollectionUtils.isNotEmpty(filter.getFilterTags()) + || CollectionUtils.isNotEmpty(filter.getFilterAccessType())) { + return; + } + validateSort(filter.getSort()); + validateQuery(filter.getQuery()); + validateFilterType(filter.getFilterType(), SUPPORTED_PACKAGE_FILTER_TYPE_VALUES); + validateFilterCustom(filter.getFilterCustom()); + validateFilterSelected(filter.getFilterSelected()); + validateProviderId(filter.getProviderId()); } - private static void validateResource(Filter filter) { - validatePackageId(filter); - validateFilterType(filter, SUPPORTED_TITLE_FILTER_TYPE_VALUES); - validateFilterSelected(filter); - validateKeywordSearch(filter, true); + 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); } - private static void validateTitle(Filter filter) { - validateFilterType(filter, SUPPORTED_TITLE_FILTER_TYPE_VALUES); - validateFilterSelected(filter); - validateFilterPackageIds(filter); - validateKeywordSearch(filter, false); + 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(Filter filter) { - if (!Sort.contains(filter.getSort().toUpperCase())) { + private static void validateSort(String sort) { + if (!Sort.contains(sort.toUpperCase())) { throw new ValidationException(INVALID_SORT_PARAMETER_MESSAGE); } } - private static void validateQuery(Filter filter) { - if ("".equals(filter.getQuery())) { + private static void validateQuery(String query) { + if ("".equals(query)) { throw new ValidationException(INVALID_QUERY_PARAMETER_MESSAGE); } } - private static void validateFilterType(Filter filter, Collection<String> supportedValues) { - if (filter.getFilterType() != null && !supportedValues.contains(filter.getFilterType())) { + 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(Filter filter) { - if (filter.getFilterCustom() != null && !Boolean.parseBoolean(filter.getFilterCustom())) { + private static void validateFilterCustom(String filterCustom) { + if (filterCustom != null && !Boolean.parseBoolean(filterCustom)) { throw new ValidationException(INVALID_FILTER_CUSTOM_PARAMETER_MESSAGE); } } - private static void validateFilterSelected(Filter filter) { - if (filter.getFilterSelected() != null - && !FILTER_SELECTED_MAPPING.containsKey(filter.getFilterSelected())) { + 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(Filter filter) { - List<String> packageIds = filter.getFilterPackageIds(); + private static void validateFilterPackageIds(List<String> packageIds) { if (packageIds != null && !packageIds.isEmpty()) { packageIds.forEach(id -> { if (!isNumeric(id)) { @@ -131,10 +125,10 @@ private static void validateFilterPackageIds(Filter filter) { } } - private static void validateKeywordSearch(Filter filter, boolean allowNullFilters) { - List<String> searchParameters = - asList(filter.getFilterName(), filter.getFilterIsxn(), - filter.getFilterSubject(), filter.getFilterPublisher()); + 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); @@ -149,15 +143,15 @@ private static void validateKeywordSearch(Filter filter, boolean allowNullFilter } } - private static void validateProviderId(Filter filter) { - if (filter.getProviderId() != null) { - IdParser.parseProviderId(filter.getProviderId()); + private static void validateProviderId(String providerId) { + if (providerId != null) { + IdParser.parseProviderId(providerId); } } - private static void validatePackageId(Filter filter) { - if (filter.getPackageId() != null) { - IdParser.parsePackageId(filter.getPackageId()); + private static void validatePackageId(String packageId) { + if (packageId != null) { + IdParser.parsePackageId(packageId); } } } 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..28a20fed0 --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java @@ -0,0 +1,80 @@ +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.Pageable; +import org.folio.repository.RecordType; +import org.folio.rest.model.query.PackageSearchParams; +import org.folio.rest.util.IdParser; + +@Value +@Builder +public class PackageRecordFilter implements Filter { + + String query; + String providerId; + String filterCustom; + String filterSelected; + String filterType; + String sort; + int page; + int count; + List<String> filterTags; + List<String> filterAccessType; + PackageSearchParams packageSearchParams; + PackageFilterParams packageFilterParams; + + @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 String resolveFilterSelected() { + return Filter.mapFilterSelected(filterSelected); + } + + public static PackageRecordFilter create(PackageSearchParams searchParams, + PackageFilterParams filterParams, + Pageable pageable) { + return PackageRecordFilter.builder() + .query(searchParams.query()) + .filterTags(filterParams.filterTags()) + .filterCustom(filterParams.filterCustom()) + .filterAccessType(filterParams.filterAccessType()) + .filterSelected(filterParams.filterSelected()) + .filterType(filterParams.filterType()) + .packageFilterParams(filterParams) + .packageSearchParams(searchParams) + .sort(pageable.sort().getValue()) + .page(pageable.page()) + .count(pageable.count()) + .build(); + } + + public static PackageRecordFilterBuilder builder() { + return new PackageRecordFilterBuilder() { + @Override + public PackageRecordFilter build() { + PackageRecordFilter filter = super.build(); + FilterValidators.validatePackage(filter); + return filter; + } + }; + } +} 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 b9b701c82..dbc176c02 100644 --- a/src/main/java/org/folio/rest/model/filter/TagFilter.java +++ b/src/main/java/org/folio/rest/model/filter/TagFilter.java @@ -19,21 +19,20 @@ public class TagFilter { int count; public static TagFilter from(Filter filter) { - RecordType recordType = filter.getRecordType(); TagFilterBuilder builder = TagFilter.builder() .tags(filter.getFilterTags()) - .recordType(recordType) + .recordType(filter.getRecordType()) .offset((filter.getPage() - 1) * filter.getCount()) .count(filter.getCount()); - switch (recordType) { - case PACKAGE -> builder.recordIdPrefix(ensureTrailingDash(filter.getProviderId())); - case RESOURCE -> builder.recordIdPrefix(ensureTrailingDash(filter.getPackageId())); - case TITLE -> { + 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 null, default -> builder.recordIdPrefix(""); + case ProviderFilter prov -> builder.recordIdPrefix(""); } return builder.build(); 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; + } + }; + } +} From 53e301ecbe6793f09b21bd6c5c4d35320c8a2e91 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 19 Jun 2026 13:17:59 +0300 Subject: [PATCH 05/16] - test validators --- .../QueryParamsValidationException.java | 19 ++++ .../rest/impl/EholdingsPackagesImpl.java | 33 ++++--- .../rest/model/filter/FilterValidator.java | 33 +++++++ .../model/filter/FilterValidatorLogic.java | 18 ++++ .../rest/model/filter/FilterValidators.java | 18 ++++ .../model/filter/PackageFilterValidator.java | 99 +++++++++++++++++++ .../model/filter/PackageRecordFilter.java | 35 +++---- .../org/folio/rest/util/RestConstants.java | 14 +++ 8 files changed, 232 insertions(+), 37 deletions(-) create mode 100644 src/main/java/org/folio/rest/exception/QueryParamsValidationException.java create mode 100644 src/main/java/org/folio/rest/model/filter/FilterValidator.java create mode 100644 src/main/java/org/folio/rest/model/filter/FilterValidatorLogic.java create mode 100644 src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java 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..72eb8ba66 --- /dev/null +++ b/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java @@ -0,0 +1,19 @@ +package org.folio.rest.exception; + +import java.io.Serial; +import java.util.List; +import lombok.Getter; + +@Getter +public class QueryParamsValidationException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + private final List<String> messageDetail; + + public QueryParamsValidationException(String message, List<String> messageDetail) { + super(message); + this.messageDetail = messageDetail; + } +} diff --git a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java index 23ee6cd64..7ebfb57ce 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -43,7 +43,6 @@ import org.folio.holdingsiq.model.Pageable; import org.folio.holdingsiq.model.RequestContext; import org.folio.holdingsiq.model.SearchType; -import org.folio.holdingsiq.model.Sort; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; import org.folio.properties.common.SearchProperties; @@ -74,11 +73,9 @@ import org.folio.rest.jaxrs.model.Tags; import org.folio.rest.jaxrs.resource.EholdingsPackages; import org.folio.rest.model.filter.AccessTypeFilter; -import org.folio.rest.model.filter.PackageFilterParams; 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.model.query.PackageSearchParams; import org.folio.rest.util.ErrorHandler; import org.folio.rest.util.ErrorUtil; import org.folio.rest.util.template.RmApiTemplate; @@ -160,12 +157,22 @@ public void getEholdingsPackages(String filterCustom, String q, String qField, S String filterFreeAccess, List<String> filterTags, List<String> filterAccessType, String sort, int page, int count, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { - var packageSearchParams = new PackageSearchParams(q, qField, qType, highlight); - var packageFilterParams = new PackageFilterParams(filterCustom, filterSelected, filterType, filterVisibility, - filterFreeAccess, filterTags, filterAccessType); - var pageable = new Pageable(page, count, Sort.valueOf(sort.toUpperCase())); - - var filter = PackageRecordFilter.create(packageSearchParams, packageFilterParams, pageable); + var filter = PackageRecordFilter.builder() + .query(q) + .queryField(qField) + .queryType(qType) + .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()) { @@ -379,13 +386,9 @@ private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitl private CompletableFuture<Packages> retrievePackages(Integer providerId, PackageRecordFilter filter, RmApiTemplateContext context) { - var filterParams = filter.getPackageFilterParams(); - var searchParams = filter.getPackageSearchParams(); var packageFilter = PackageFilter.builder() - .query(searchParams.query()) - .searchType(searchParams.queryType() == null - ? SearchType.fromValue(searchProperties.packagesSearchType()) - : SearchType.fromValue(searchParams.queryType())) + .query(filter.getQuery()) + .searchType(filter.getSearchType().orElse(SearchType.fromValue(searchProperties.packagesSearchType()))) .searchField(PackageSearchField.fromValue(searchParams.queryField())) .highlightTag(searchParams.highlight() ? searchProperties.highlightTag() : null) .filterSelected(PackageFilterSelected.fromValue(filterParams.filterSelected())) 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..ec3ac1ccd --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/FilterValidator.java @@ -0,0 +1,33 @@ +package org.folio.rest.model.filter; + +import java.util.List; +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 { + + List<String> 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 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 index 8a0dd5df8..86f920126 100644 --- a/src/main/java/org/folio/rest/model/filter/FilterValidators.java +++ b/src/main/java/org/folio/rest/model/filter/FilterValidators.java @@ -14,6 +14,8 @@ 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; @@ -21,6 +23,8 @@ 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]"; @@ -53,6 +57,8 @@ public static void validatePackage(PackageRecordFilter filter) { } 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()); @@ -97,6 +103,18 @@ private static void validateQuery(String query) { } } + 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); 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..3d5b4489b --- /dev/null +++ b/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java @@ -0,0 +1,99 @@ +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.Collections; +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.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 List<String> validate(@NonNull PackageRecordFilter filter) { + if (isNotEmpty(filter.getFilterTags()) + || isNotEmpty(filter.getFilterAccessType())) { + return Collections.emptyList(); + } + return VALIDATORS.stream() + .map(logic -> validate(filter, logic)) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + } + + private static boolean isFilterFreeAccessValid(String filterFreeAccess) { + return filterFreeAccess != null && !FILTER_FREE_ACCESS_MAPPING.containsKey(filterFreeAccess); + } + + private static boolean isFilterVisibilityValid(String filterVisibility) { + return filterVisibility != null && !FILTER_VISIBILITY_MAPPING.containsKey(filterVisibility); + } + + private static boolean isFilterSelectedValid(String filterSelected) { + return filterSelected != null && !FILTER_SELECTED_MAPPING.containsKey(filterSelected); + } + + private static boolean isFilterCustomValid(String filterCustom) { + return filterCustom != null && !Boolean.parseBoolean(filterCustom); + } + + private static boolean isFilterTypeValid(String filterType) { + return filterType != null && !SUPPORTED_PACKAGE_FILTER_TYPE_VALUES.contains(filterType); + } + + private static boolean isQueryValid(String anObject) { + return "".equals(anObject); + } + + private static boolean isQueryFieldValid(String queryField) { + return !PackageSearchField.contains(queryField.toUpperCase()); + } + + private static boolean isQueryTypeValid(String queryType) { + return !SearchType.contains(queryType.toUpperCase()); + } + + 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 index 28a20fed0..610905cbe 100644 --- a/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java +++ b/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java @@ -3,11 +3,11 @@ 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.Pageable; +import org.folio.holdingsiq.model.SearchType; import org.folio.repository.RecordType; -import org.folio.rest.model.query.PackageSearchParams; import org.folio.rest.util.IdParser; @Value @@ -15,17 +15,26 @@ public class PackageRecordFilter implements Filter { 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; - PackageSearchParams packageSearchParams; - PackageFilterParams packageFilterParams; + + public Optional<SearchType> getSearchType() { + return Optional.ofNullable(queryType) + .map(SearchType::fromValue); + } @Override public RecordType getRecordType() { @@ -49,24 +58,6 @@ public String resolveFilterSelected() { return Filter.mapFilterSelected(filterSelected); } - public static PackageRecordFilter create(PackageSearchParams searchParams, - PackageFilterParams filterParams, - Pageable pageable) { - return PackageRecordFilter.builder() - .query(searchParams.query()) - .filterTags(filterParams.filterTags()) - .filterCustom(filterParams.filterCustom()) - .filterAccessType(filterParams.filterAccessType()) - .filterSelected(filterParams.filterSelected()) - .filterType(filterParams.filterType()) - .packageFilterParams(filterParams) - .packageSearchParams(searchParams) - .sort(pageable.sort().getValue()) - .page(pageable.page()) - .count(pageable.count()) - .build(); - } - public static PackageRecordFilterBuilder builder() { return new PackageRecordFilterBuilder() { @Override diff --git a/src/main/java/org/folio/rest/util/RestConstants.java b/src/main/java/org/folio/rest/util/RestConstants.java index fedaca56a..d87bfef62 100644 --- a/src/main/java/org/folio/rest/util/RestConstants.java +++ b/src/main/java/org/folio/rest/util/RestConstants.java @@ -2,6 +2,8 @@ import java.util.List; import java.util.Map; +import org.folio.holdingsiq.model.PackageFilterFreeAccess; +import org.folio.holdingsiq.model.PackageFilterVisibility; import org.folio.rest.jaxrs.model.JsonAPI; public final class RestConstants { @@ -30,6 +32,18 @@ public final class RestConstants { 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("true", PackageFilterFreeAccess.TRUE, + "false", PackageFilterFreeAccess.FALSE); + public static final List<String> SUPPORTED_TITLE_FILTER_TYPE_VALUES = List.of("audiobook", "book", "bookseries", "database", "journal", "newsletter", "newspaper", "proceedings", "report", From 65b3425c5bbdff012a48984e3693a2c30f2d8f9a Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 19 Jun 2026 11:04:02 +0300 Subject: [PATCH 06/16] - test2 --- ramls/packages.raml | 5 +-- ramls/providers.raml | 2 +- ramls/traits/filterable.raml | 16 --------- ramls/traits/packageFilterable.raml | 33 +++++++++++++++++++ ramls/traits/packageQueriable.raml | 27 +++++++++++++++ .../properties/common/SearchProperties.java | 6 +++- .../model/filter/PackageFilterParams.java | 13 ++++++++ .../rest/model/query/PackageSearchParams.java | 8 +++++ .../spring/config/ApplicationConfig.java | 6 ++-- src/main/resources/application.properties | 1 + .../rmapi/packages/put-package-custom.json | 9 +++-- 11 files changed, 102 insertions(+), 24 deletions(-) delete mode 100644 ramls/traits/filterable.raml create mode 100644 ramls/traits/packageFilterable.raml create mode 100644 ramls/traits/packageQueriable.raml create mode 100644 src/main/java/org/folio/rest/model/filter/PackageFilterParams.java create mode 100644 src/main/java/org/folio/rest/model/query/PackageSearchParams.java 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..11169a897 100644 --- a/ramls/providers.raml +++ b/ramls/providers.raml @@ -22,7 +22,7 @@ traits: queriable: !include traits/queriable.raml sortable: !include traits/sortable.raml pageable: !include traits/pageable.raml - filterable: !include traits/filterable.raml + filterable: !include traits/packageFilterable.raml taggable: !include traits/taggable.raml accessible: !include traits/accessible.raml includable: !include traits/includePackages.raml 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/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/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/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/spring/config/ApplicationConfig.java b/src/main/java/org/folio/spring/config/ApplicationConfig.java index 2fa213a01..7fe0cba86 100644 --- a/src/main/java/org/folio/spring/config/ApplicationConfig.java +++ b/src/main/java/org/folio/spring/config/ApplicationConfig.java @@ -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.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/resources/requests/rmapi/packages/put-package-custom.json b/src/test/resources/requests/rmapi/packages/put-package-custom.json index 77c4a2901..1532dd3ff 100644 --- a/src/test/resources/requests/rmapi/packages/put-package-custom.json +++ b/src/test/resources/requests/rmapi/packages/put-package-custom.json @@ -2,8 +2,13 @@ "contentType": 8, "isSelected": true, "customAltNames": [ - "Name of the ages (custom name)", - "Another custom name" + { + "id": 1234, + "altName": "Name of the ages (custom name)" + }, + { + "altName": "Another custom name" + } ], "customDisplayName": "Name of The Ages (2026)", "customCoverage": { From 0290ab964c22183c5c3a272196bdc29838c902ca Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 19 Jun 2026 16:20:15 +0300 Subject: [PATCH 07/16] fixes --- ramls/providers.raml | 5 +- ramls/types/packages/packageVisibility.json | 2 +- src/main/java/org/folio/common/ListUtils.java | 7 + .../aspect/ValidationErrorHandlerAspect.aj | 51 ++-- .../PackageCollectionItemConverter.java | 10 +- .../packages/PackageRequestConverter.java | 2 +- .../QueryParamsValidationException.java | 10 +- .../rest/impl/EholdingsPackagesImpl.java | 79 ++---- .../rest/impl/EholdingsProvidersImpl.java | 53 ++-- .../org/folio/rest/model/filter/Filter.java | 8 +- .../rest/model/filter/FilterValidator.java | 5 +- .../model/filter/PackageFilterValidator.java | 50 +++- .../model/filter/PackageRecordFilter.java | 68 +++-- .../java/org/folio/rest/util/ErrorUtil.java | 9 + .../org/folio/rest/util/RestConstants.java | 13 +- .../validator/PackagePutBodyValidator.java | 13 +- src/main/resources/application-dev.properties | 1 + .../EholdingsPackagesTest.java | 120 ++++----- .../java/org/folio/util/PackagesTestUtil.java | 2 +- ...ut-package-custom-multiple-attributes.json | 11 +- .../put-package-custom-with-access-type.json | 11 +- ...package-not-selected-non-empty-fields.json | 11 +- ...put-package-selected-with-access-type.json | 11 +- .../package/put-package-selected.json | 31 ++- .../put-package-with-invalid-access-type.json | 11 +- ...-package-with-not-existed-access-type.json | 11 +- .../rmapi/packages/put-package-custom.json | 28 +- .../packages/put-package-is-selected.json | 48 +++- .../expected-package-by-id-with-provider.json | 128 ++++----- .../packages/expected-package-by-id.json | 46 ++-- ...package-collection-with-five-elements.json | 252 +++++++++++++----- ...d-package-collection-with-one-element.json | 79 +++--- .../get-created-package-response.json | 81 +++--- .../get-custom-package-by-id-response.json | 13 +- .../get-package-by-id-2-response.json | 13 +- .../get-package-by-id-for-resource.json | 11 +- .../packages/get-package-by-id-response.json | 13 +- .../packages/get-packages-by-provider-id.json | 11 +- .../rmapi/packages/get-packages-response.json | 88 ++++-- .../rmapi/packages/post-package-request.json | 13 - .../resources/test-application.properties | 1 + 41 files changed, 864 insertions(+), 566 deletions(-) delete mode 100644 src/test/resources/responses/rmapi/packages/post-package-request.json diff --git a/ramls/providers.raml b/ramls/providers.raml index 11169a897..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/packageFilterable.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/types/packages/packageVisibility.json b/ramls/types/packages/packageVisibility.json index d2c0d167b..a33e5d7fa 100644 --- a/ramls/types/packages/packageVisibility.json +++ b/ramls/types/packages/packageVisibility.json @@ -26,6 +26,6 @@ }, "required": [ "category", - "reason" + "hidden" ] } 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 <T, R> List<R> mapItems(Collection<T> source, Function<? super T, return source.stream().map(mapper).collect(Collectors.toList()); } + public static <T, R> List<R> mapItemsNullable(Collection<T> source, Function<? super T, ? extends R> 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/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<AsyncResult<Response>> asyncResultHandler) : execution(@HandleValidationErrors * *(.., Handler, *)) && args(.., asyncResultHandler, *); + pointcut validatedMethodCall( + Handler<AsyncResult<Response>> asyncResultHandler): execution(@HandleValidationErrors * *(.., Handler, *)) && args(.., asyncResultHandler, *); @SuppressAjWarnings({"adviceDidNotMatch"}) - void around(Handler asyncResultHandler) : validatedMethodCall(asyncResultHandler) { - try{ + void around(Handler<AsyncResult<Response>> 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/packages/PackageCollectionItemConverter.java b/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java index 149bb64f2..8ae6abd12 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java @@ -1,6 +1,6 @@ package org.folio.rest.converter.packages; -import static org.folio.common.ListUtils.mapItems; +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; @@ -33,7 +33,7 @@ private PackageDataAttributes convertAttributes(PackageData packageData) { return new PackageDataAttributes() .withAllowKbToAddTitles(packageData.getAllowEbscoToAddTitles()) .withContentType(CONTENT_TYPES.get(packageData.getContentType().toLowerCase())) - .withCustomAltNames(mapItems(packageData.getCustomAltNames(), this::convertAltName)) + .withCustomAltNames(mapItemsNullable(packageData.getCustomAltNames(), this::convertAltName)) .withCustomCoverage(convertCustomCoverage(packageData)) .withCustomDescription(packageData.getCustomDescription()) .withCustomDisplayName(packageData.getCustomDisplayName()) @@ -42,7 +42,7 @@ private PackageDataAttributes convertAttributes(PackageData packageData) { .withIsFreeAccess(packageData.getPackageFreeAccess()) .withIsPrimaryPackage(packageData.getIsPrimaryPackage()) .withIsSelected(packageData.getIsSelected()) - .withManagedAltNames(mapItems(packageData.getManagedAltNames(), this::convertAltName)) + .withManagedAltNames(mapItemsNullable(packageData.getManagedAltNames(), this::convertAltName)) .withManagedDescription(packageData.getManagedDescription()) .withName(packageData.getPackageName()) .withPackageId(packageData.getPackageId()) @@ -53,7 +53,7 @@ private PackageDataAttributes convertAttributes(PackageData packageData) { .withSelectedCount(packageData.getSelectedCount()) .withTitleCount(packageData.getTitleCount()) .withUrl(packageData.getPackageUrl()) - .withVisibility(mapItems(packageData.getVisibilityDetails(), this::convertVisibility)); + .withVisibility(mapItemsNullable(packageData.getVisibilityDetails(), this::convertVisibility)); } private PackageVisibility convertVisibility(Visibility visibility) { @@ -71,7 +71,7 @@ private Coverage convertCustomCoverage(PackageData packageData) { private PackageAltName convertAltName(AlternateName alternateName) { return new PackageAltName() - .withId(alternateName.id() == null ? null : Integer.parseInt(alternateName.id())) + .withId(alternateName.id() == null ? null : alternateName.id()) .withAltName(alternateName.altName()); } } 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 e52a1dee3..dd35cc5dd 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java @@ -65,7 +65,7 @@ private PackagePut.PackagePutBuilder convertCommonAttributesToPackagePutRequest( if (attributes.getCustomAltNames() != null) { builder.customAltNames(mapItems(attributes.getCustomAltNames(), - packageAltName -> new AlternateName(null, packageAltName.getAltName()))); + packageAltName -> new AlternateName(packageAltName.getId(), packageAltName.getAltName()))); } builder.customDescription(attributes.getCustomDescription()); diff --git a/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java b/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java index 72eb8ba66..086f824a0 100644 --- a/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java +++ b/src/main/java/org/folio/rest/exception/QueryParamsValidationException.java @@ -2,9 +2,7 @@ import java.io.Serial; import java.util.List; -import lombok.Getter; -@Getter public class QueryParamsValidationException extends RuntimeException { @Serial @@ -12,8 +10,12 @@ public class QueryParamsValidationException extends RuntimeException { private final List<String> messageDetail; - public QueryParamsValidationException(String message, List<String> messageDetail) { - super(message); + public QueryParamsValidationException(List<String> messageDetail) { + super("Query params validation failed."); this.messageDetail = messageDetail; } + + public List<String> 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 7ebfb57ce..9a6dd172e 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsPackagesImpl.java @@ -30,19 +30,11 @@ import org.folio.config.cache.VendorIdCacheKey; import org.folio.holdingsiq.model.CustomerResources; import org.folio.holdingsiq.model.PackageData; -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.PackageId; import org.folio.holdingsiq.model.PackagePost; import org.folio.holdingsiq.model.PackagePut; -import org.folio.holdingsiq.model.PackageSearchField; import org.folio.holdingsiq.model.Packages; -import org.folio.holdingsiq.model.Pageable; import org.folio.holdingsiq.model.RequestContext; -import org.folio.holdingsiq.model.SearchType; import org.folio.holdingsiq.model.Titles; import org.folio.holdingsiq.service.exception.ResourceNotFoundException; import org.folio.properties.common.SearchProperties; @@ -149,18 +141,19 @@ public EholdingsPackagesImpl() { SpringContextUtil.autowireDependencies(this, Vertx.currentContext()); } + @SuppressWarnings("checkstyle:MethodLength") @Override @Validate @HandleValidationErrors - public void getEholdingsPackages(String filterCustom, String q, String qField, String qType, boolean highlight, - String filterSelected, String filterType, String filterVisibility, + public void getEholdingsPackages(String filterCustom, String q, String queryField, String queryType, + boolean highlight, String filterSelected, String filterType, String filterVisibility, String filterFreeAccess, List<String> filterTags, List<String> filterAccessType, String sort, int page, int count, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { var filter = PackageRecordFilter.builder() .query(q) - .queryField(qField) - .queryType(qType) + .queryField(queryField) + .queryType(queryType) .highlight(highlight) .filterCustom(filterCustom) .filterSelected(filterSelected) @@ -289,6 +282,7 @@ public void deleteEholdingsPackagesByPackageId(String packageId, Map<String, Str .execute(); } + @SuppressWarnings("checkstyle:MethodLength") @Override @Validate @HandleValidationErrors @@ -302,19 +296,19 @@ public void getEholdingsPackagesResourcesByPackageId(String packageId, List<Stri Context vertxContext) { 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(); + .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); @@ -386,44 +380,13 @@ private Function<RmApiTemplateContext, CompletableFuture<?>> retrievePackageTitl private CompletableFuture<Packages> retrievePackages(Integer providerId, PackageRecordFilter filter, RmApiTemplateContext context) { - var packageFilter = PackageFilter.builder() - .query(filter.getQuery()) - .searchType(filter.getSearchType().orElse(SearchType.fromValue(searchProperties.packagesSearchType()))) - .searchField(PackageSearchField.fromValue(searchParams.queryField())) - .highlightTag(searchParams.highlight() ? searchProperties.highlightTag() : null) - .filterSelected(PackageFilterSelected.fromValue(filterParams.filterSelected())) - .filterType(PackageFilterType.fromValue(filterParams.filterType())) - .filterPackageFreeAccess(toFilterPackageFreeAccess(filterParams.filterFreeAccess())) - .filterVisibility(toFilterVisibility(filterParams.filterVisibility())) - .build(); - var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.resolveSort()); + var packageFilter = filter.toClientFilter(searchProperties); + var pageable = filter.toPageable(); return providerId == null ? context.getPackagesService().retrievePackages(packageFilter, pageable) : context.getPackagesService().retrievePackages(providerId, packageFilter, pageable); } - private PackageFilterVisibility toFilterVisibility(String source) { - return switch (source) { - case "visibleInPF" -> PackageFilterVisibility.VISIBLE_IN_PF; - case "visibleInFTF" -> PackageFilterVisibility.VISIBLE_IN_FTF; - case "visibleInMARC" -> PackageFilterVisibility.INCLUDED_IN_MARC; - case "hiddenInPF" -> PackageFilterVisibility.HIDDEN_IN_PF; - case "hiddenInFTF" -> PackageFilterVisibility.HIDDEN_IN_FTF; - case "hiddenInMARC" -> PackageFilterVisibility.EXCLUDED_FROM_MARC; - case null -> null; - default -> throw new IllegalStateException("Unexpected value: " + source); - }; - } - - private PackageFilterFreeAccess toFilterPackageFreeAccess(String source) { - return switch (source) { - case "public" -> PackageFilterFreeAccess.TRUE; - case "controlled" -> PackageFilterFreeAccess.FALSE; - case null -> null; - default -> throw new IllegalStateException("Unexpected value: " + source); - }; - } - private CompletableFuture<PackageResult> updateAccessTypeMapping(AccessType accessType, PackageResult packageResult, RmApiTemplateContext context) { diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index 3b51c5195..b3682fc7b 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -21,16 +21,12 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Function; import javax.ws.rs.core.Response; -import org.folio.holdingsiq.model.PackageFilter; -import org.folio.holdingsiq.model.PackageFilterSelected; -import org.folio.holdingsiq.model.PackageFilterType; import org.folio.holdingsiq.model.Packages; -import org.folio.holdingsiq.model.Pageable; import org.folio.holdingsiq.model.RequestContext; -import org.folio.holdingsiq.model.SearchType; 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; @@ -70,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") @@ -99,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()); @@ -194,26 +189,31 @@ tags, new RequestContext(headers).getTenant()) }); } + @SuppressWarnings("checkstyle:MethodLength") @Override - @Validate - @HandleValidationErrors - public void getEholdingsProvidersPackagesByProviderId(String providerId, String q, List<String> filterTags, + public void getEholdingsProvidersPackagesByProviderId(String providerId, String q, String queryField, + String queryType, boolean highlight, List<String> filterTags, List<String> filterAccessType, String filterSelected, - String filterType, String sort, int page, int count, + String filterType, String filterVisibility, String filterAccess, + String sort, int page, int count, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { var filter = PackageRecordFilter.builder() - .query(q) - .filterTags(filterTags) - .providerId(providerId) - .filterAccessType(filterAccessType) - .filterSelected(filterSelected) - .filterType(filterType) - .sort(sort) - .page(page) - .count(count) - .build(); + .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()) { @@ -234,13 +234,8 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String } private Function<RmApiTemplateContext, CompletableFuture<?>> retrieveFilteredPackages(PackageRecordFilter filter) { - var packageFilter = PackageFilter.builder() - .query(filter.getQuery()) - .filterSelected(PackageFilterSelected.fromValue(filter.resolveFilterSelected())) - .filterType(PackageFilterType.fromValue(filter.getFilterType())) - .searchType(SearchType.fromValue(packagesSearchType)) - .build(); - var pageable = new Pageable(filter.getPage(), filter.getCount(), filter.resolveSort()); + var packageFilter = filter.toClientFilter(searchProperties); + var pageable = filter.toPageable(); return context -> context.getPackagesService() .retrievePackages(filter.parseProviderId(), packageFilter, pageable) 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 2c9b5ea51..9a4770265 100644 --- a/src/main/java/org/folio/rest/model/filter/Filter.java +++ b/src/main/java/org/folio/rest/model/filter/Filter.java @@ -7,12 +7,12 @@ import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.folio.holdingsiq.model.Pageable; import org.folio.holdingsiq.model.Sort; import org.folio.repository.RecordType; public sealed interface Filter permits ProviderFilter, PackageRecordFilter, ResourceFilter, TitleFilter { - // Common getters (implemented by each @Value class via Lombok) String getSort(); int getPage(); @@ -41,6 +41,10 @@ default boolean isAccessTypeFilter() { return isFilteredBy(getFilterAccessType(), getFilterTags()); } + default Pageable toPageable() { + return new Pageable(getPage(), getCount(), resolveSort()); + } + // Private helper private boolean isFilteredBy(List<String> primary, List<String> other) { return isNotEmpty(primary) @@ -51,6 +55,6 @@ && matchesAll(primary, StringUtils::isNotBlank) // Shared utility for resolveFilterSelected (used by 3 implementations) static String mapFilterSelected(String filterSelected) { - return filterSelected == null ? null : FILTER_SELECTED_MAPPING.get(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 index ec3ac1ccd..45dd20de4 100644 --- a/src/main/java/org/folio/rest/model/filter/FilterValidator.java +++ b/src/main/java/org/folio/rest/model/filter/FilterValidator.java @@ -1,6 +1,5 @@ package org.folio.rest.model.filter; -import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; @@ -8,7 +7,7 @@ public sealed interface FilterValidator<F extends Filter> permits PackageFilterValidator { - List<String> validate(@NonNull F filter); + void validate(@NonNull F filter); default Optional<String> validate(@NonNull F filter, @NonNull Function<F, String> paramExtractor, @@ -22,7 +21,7 @@ default Optional<String> validate(@NonNull F filter, } } - default Optional<String> validate(@NonNull F filter, @NonNull FilterValidatorLogic logic) { + 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(); diff --git a/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java b/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java index 3d5b4489b..d173b981d 100644 --- a/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java +++ b/src/main/java/org/folio/rest/model/filter/PackageFilterValidator.java @@ -7,12 +7,12 @@ 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.Collections; 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> { @@ -49,51 +49,75 @@ public final class PackageFilterValidator implements FilterValidator<PackageReco ); @Override - public List<String> validate(@NonNull PackageRecordFilter filter) { + public void validate(@NonNull PackageRecordFilter filter) { if (isNotEmpty(filter.getFilterTags()) || isNotEmpty(filter.getFilterAccessType())) { - return Collections.emptyList(); + return; } - return VALIDATORS.stream() + 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) { - return filterFreeAccess != null && !FILTER_FREE_ACCESS_MAPPING.containsKey(filterFreeAccess); + if (filterFreeAccess == null) { + return true; + } + return FILTER_FREE_ACCESS_MAPPING.containsKey(filterFreeAccess); } private static boolean isFilterVisibilityValid(String filterVisibility) { - return filterVisibility != null && !FILTER_VISIBILITY_MAPPING.containsKey(filterVisibility); + if (filterVisibility == null) { + return true; + } + return FILTER_VISIBILITY_MAPPING.containsKey(filterVisibility); } private static boolean isFilterSelectedValid(String filterSelected) { - return filterSelected != null && !FILTER_SELECTED_MAPPING.containsKey(filterSelected); + if (filterSelected == null) { + return true; + } + return FILTER_SELECTED_MAPPING.containsKey(filterSelected); } private static boolean isFilterCustomValid(String filterCustom) { - return filterCustom != null && !Boolean.parseBoolean(filterCustom); + if (filterCustom == null) { + return true; + } + return Boolean.parseBoolean(filterCustom); } private static boolean isFilterTypeValid(String filterType) { - return filterType != null && !SUPPORTED_PACKAGE_FILTER_TYPE_VALUES.contains(filterType); + if (filterType == null) { + return true; + } + return SUPPORTED_PACKAGE_FILTER_TYPE_VALUES.contains(filterType); } private static boolean isQueryValid(String anObject) { - return "".equals(anObject); + return !"".equals(anObject); } private static boolean isQueryFieldValid(String queryField) { - return !PackageSearchField.contains(queryField.toUpperCase()); + if (queryField == null) { + return true; + } + return PackageSearchField.contains(queryField); } private static boolean isQueryTypeValid(String queryType) { - return !SearchType.contains(queryType.toUpperCase()); + if (queryType == null) { + return true; + } + return SearchType.contains(queryType); } private static boolean isSortValid(String sort) { - return !Sort.contains(sort.toUpperCase()); + 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 index 610905cbe..111d56e72 100644 --- a/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java +++ b/src/main/java/org/folio/rest/model/filter/PackageRecordFilter.java @@ -6,14 +6,24 @@ 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; @@ -31,9 +41,39 @@ public class PackageRecordFilter implements Filter { 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); + 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 @@ -54,18 +94,16 @@ public Boolean resolveFilterCustom() { return filterCustom == null ? null : Boolean.parseBoolean(filterCustom); } - public String resolveFilterSelected() { - return Filter.mapFilterSelected(filterSelected); - } - - public static PackageRecordFilterBuilder builder() { - return new PackageRecordFilterBuilder() { - @Override - public PackageRecordFilter build() { - PackageRecordFilter filter = super.build(); - FilterValidators.validatePackage(filter); - return filter; - } - }; + 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/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/RestConstants.java b/src/main/java/org/folio/rest/util/RestConstants.java index d87bfef62..4e61c9aae 100644 --- a/src/main/java/org/folio/rest/util/RestConstants.java +++ b/src/main/java/org/folio/rest/util/RestConstants.java @@ -3,6 +3,7 @@ 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; @@ -21,11 +22,11 @@ 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 = @@ -41,8 +42,8 @@ public final class RestConstants { "hiddenInMARC", PackageFilterVisibility.EXCLUDED_FROM_MARC); public static final Map<String, PackageFilterFreeAccess> FILTER_FREE_ACCESS_MAPPING = - Map.of("true", PackageFilterFreeAccess.TRUE, - "false", PackageFilterFreeAccess.FALSE); + 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", diff --git a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java b/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java index 2160b3c92..718884207 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,8 +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) { @@ -30,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.checkIsNull("visibility", visibility); ValidatorUtil.checkIsEmpty("customCoverage.beginCoverage", beginCoverage); ValidatorUtil.checkIsEmpty("customCoverage.endCoverage", endCoverage); ValidatorUtil.checkIsNull("packageToken.value", value); 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/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java index 14195d622..11ee2b500 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java @@ -8,6 +8,7 @@ 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.urlPathEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.verify; import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; import static java.lang.String.format; @@ -160,10 +161,11 @@ public class EholdingsPackagesTest extends WireMockTestBase { 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 LISTS_STUB_URL = "/rm/rmaccounts/v2/" + STUB_CUSTOMER_ID + "/lists"; + private static final String LIST_BY_ID_STUB_URL = LISTS_STUB_URL + "/" + STUB_PACKAGE_ID; + private static final String LIST_BY_ID_2_STUB_URL = LISTS_STUB_URL + "/" + STUB_PACKAGE_ID_2; 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"; @@ -198,7 +200,7 @@ public void shouldReturnPackagesOnGet() throws IOException, URISyntaxException, 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); + packages, true); } @Test @@ -228,7 +230,7 @@ public void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByTags 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); + mockGet(new RegexPattern(".*lists/.*"), HttpStatus.SC_INTERNAL_SERVER_ERROR); PackageCollection packageCollection = getWithOk(PACKAGES_ENDPOINT + "?filter[tags]=" + STUB_TAG_VALUE, STUB_USER_ID_HEADER).as(PackageCollection.class); @@ -282,7 +284,7 @@ public void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByAcce 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); + mockGet(new RegexPattern(".*lists/.*"), 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); @@ -316,19 +318,19 @@ public void shouldReturnPackagesOnGetWithPackageId() throws IOException, URISynt 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.*"), + mockGet(new RegexPattern("/rm/rmaccounts/v2/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/lists.*"), 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); + packages, true); } @Test public void shouldReturnPackagesOnGetById() throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); String packageData = getWithOk(PACKAGES_PATH, STUB_USER_ID_HEADER).asString(); @@ -339,7 +341,7 @@ public void shouldReturnPackagesOnGetById() throws IOException, URISyntaxExcepti 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); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); Package packageData = getWithOk(PACKAGES_ENDPOINT + "/" + packageId, STUB_USER_ID_HEADER).as(Package.class); @@ -352,7 +354,7 @@ public void shouldReturnPackageWithAccessTypeOnGetById() throws IOException, URI String expectedAccessTypeId = accessTypes.getFirst().getId(); insertAccessTypeMapping(FULL_PACKAGE_ID, PACKAGE, expectedAccessTypeId, vertx); - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); Package packageData = getWithOk(PACKAGES_ENDPOINT + "/" + FULL_PACKAGE_ID, STUB_USER_ID_HEADER).as(Package.class); assertNotNull(packageData.getIncluded()); @@ -424,10 +426,10 @@ public void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() throws IOExceptio 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); + mockGet(new EqualToPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - mockPut(new EqualToPattern(PACKAGE_BY_ID_URL), putBodyPattern, SC_NO_CONTENT); + mockPut(new EqualToPattern(LIST_BY_ID_STUB_URL), putBodyPattern, SC_NO_CONTENT); deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); @@ -440,10 +442,10 @@ public void shouldDeletePackageAccessTypeMappingOnDelete() throws IOException, U 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); + mockGet(new EqualToPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - mockPut(new EqualToPattern(PACKAGE_BY_ID_URL), putBodyPattern, SC_NO_CONTENT); + mockPut(new EqualToPattern(LIST_BY_ID_STUB_URL), putBodyPattern, SC_NO_CONTENT); deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); @@ -456,8 +458,8 @@ public void shouldDeletePackageOnDeleteRequest() throws IOException, URISyntaxEx 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); + mockGet(new EqualToPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); + mockPut(new EqualToPattern(LIST_BY_ID_STUB_URL), new AnythingPattern(), SC_NO_CONTENT); deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); @@ -467,7 +469,7 @@ public void shouldDeletePackageOnDeleteRequest() throws IOException, URISyntaxEx @Test public void shouldReturn404WhenPackageIsNotFoundOnRmApi() { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), SC_NOT_FOUND); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), SC_NOT_FOUND); JsonapiError error = getWithStatus(PACKAGES_PATH, SC_NOT_FOUND, STUB_USER_ID_HEADER).as(JsonapiError.class); @@ -477,7 +479,7 @@ public void shouldReturn404WhenPackageIsNotFoundOnRmApi() { @Test public void shouldReturnResourcesWhenIncludedFlagIsSetToResources() throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); mockResourceById(RESOURCES_BY_PACKAGE_ID_STUB_FILE); Package packageData = getWithOk(PACKAGES_PATH + "?include=resources", STUB_USER_ID_HEADER) @@ -494,27 +496,27 @@ public void shouldReturnResourcesWhenIncludedFlagIsSetToResources() @Test public void shouldReturnProviderWhenIncludedFlagIsSetToProvider() throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(PACKAGE_BY_ID_URL), CUSTOM_PACKAGE_STUB_FILE); + mockGet(new RegexPattern(LIST_BY_ID_STUB_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); + JSONAssert.assertEquals(expected, actual, true); } @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); + mockGet(new EqualToPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); - mockPut(new EqualToPattern(PACKAGE_BY_ID_URL), putBodyPattern, SC_NO_CONTENT); + mockPut(new EqualToPattern(LIST_BY_ID_STUB_URL), putBodyPattern, SC_NO_CONTENT); deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); - verify(1, putRequestedFor(PACKAGE_URL_PATTERN) + verify(1, putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .withRequestBody(putBodyPattern)); } @@ -532,7 +534,7 @@ public void shouldReturn400WhenPackageIsNotCustom() throws URISyntaxException, I .toBuilder().isCustom(false).build(); stubFor( - get(PACKAGE_URL_PATTERN) + get(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .willReturn(new ResponseDefinitionBuilder() .withBody(mapper.writeValueAsString(packageData)))); @@ -555,7 +557,7 @@ public void shouldReturn200WhenSelectingPackage() throws URISyntaxException, IOE assertEquals(updatedIsSelected, actualPackage.getData().getAttributes().getIsSelected()); - verify(putRequestedFor(PACKAGE_URL_PATTERN) + verify(putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-is-selected.json"), true, true))); } @@ -574,7 +576,7 @@ public void shouldUpdateAllAttributesInSelectedPackage() throws URISyntaxExcepti 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) + verify(putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-is-selected.json"), true, true))); assertEquals(updatedSelected, actualPackage.getData().getAttributes().getIsSelected()); @@ -605,12 +607,8 @@ public void shouldUpdateAllAttributesInSelectedPackageAndCreateNewAccessTypeMapp 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()); @@ -642,11 +640,11 @@ public void shouldDeleteAccessTypeMappingWhenRmApiSend404() throws URISyntaxExce String putBody = format(readFile("requests/kb-ebsco/package/put-package-custom-with-access-type.json"), newAccessTypeId); - stubFor(get(PACKAGE_URL_PATTERN).inScenario("Put package") + stubFor(get(urlPathEqualTo(LIST_BY_ID_STUB_URL)).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") + stubFor(get(urlPathEqualTo(LIST_BY_ID_STUB_URL)).inScenario("Put package") .whenScenarioStateIs("Not found") .willReturn(new ResponseDefinitionBuilder().withStatus(SC_NOT_FOUND))); @@ -659,23 +657,23 @@ public void shouldDeleteAccessTypeMappingWhenRmApiSend404() throws URISyntaxExce @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); + mockGet(new RegexPattern(LIST_BY_ID_STUB_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)); + verify(0, putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL))); - assertErrorContainsTitle(error, "Invalid visibilityData.isHidden"); + assertErrorContainsTitle(error, "Invalid visibility"); } @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); + mockGet(new RegexPattern(LIST_BY_ID_STUB_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)); + verify(0, putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL))); assertErrorContainsTitle(error, "Package isCustom not matched"); } @@ -696,7 +694,7 @@ public void shouldPassIsFullPackageAttributeToRmApi() throws URISyntaxException, mapper.readValue(readFile("requests/rmapi/packages/put-package-is-selected.json"), PackagePut.class) .toBuilder().isFullPackage(false).build(); - verify(putRequestedFor(PACKAGE_URL_PATTERN) + verify(putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .withRequestBody(equalToJson(mapper.writeValueAsString(rmApiPutRequest), true, true))); } @@ -717,11 +715,10 @@ public void shouldUpdateAllAttributesInCustomPackage() throws URISyntaxException readFile("requests/kb-ebsco/package/put-package-custom-multiple-attributes.json"), STUB_USER_ID_HEADER).as(Package.class); - verify(putRequestedFor(PACKAGE_URL_PATTERN) + verify(putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .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()); @@ -749,11 +746,10 @@ public void shouldUpdateAllAttributesInCustomPackageAndCreateNewAccessTypeMappin accessTypeId); Package actualPackage = putWithOk(PACKAGES_PATH, putBody, STUB_USER_ID_HEADER).as(Package.class); - verify(putRequestedFor(PACKAGE_URL_PATTERN) + verify(putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .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()); @@ -791,11 +787,10 @@ public void shouldUpdateAllAttributesInCustomPackageAndDeleteAccessTypeMapping() 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) + verify(putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .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()); @@ -832,11 +827,10 @@ public void shouldUpdateAllAttributesInCustomPackageAndUpdateAccessTypeMapping() newAccessTypeId); Package actualPackage = putWithOk(PACKAGES_PATH, putBody, STUB_USER_ID_HEADER).as(Package.class); - verify(putRequestedFor(PACKAGE_URL_PATTERN) + verify(putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .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()); @@ -855,7 +849,7 @@ public void shouldUpdateAllAttributesInCustomPackageAndUpdateAccessTypeMapping() @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); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); JsonapiError error = putWithStatus(PACKAGES_PATH, requestBody, SC_BAD_REQUEST, CONTENT_TYPE_HEADER, STUB_USER_ID_HEADER) @@ -880,7 +874,7 @@ public void shouldReturn422OnPutPackageWithInvalidAccessTypeId() throws URISynta @Test public void shouldReturn400WhenRmApiReturns400() throws URISyntaxException, IOException { - EqualToPattern urlPattern = new EqualToPattern(PACKAGE_BY_ID_URL); + EqualToPattern urlPattern = new EqualToPattern(LIST_BY_ID_STUB_URL); mockGet(urlPattern, PACKAGE_STUB_FILE); mockPut(urlPattern, SC_BAD_REQUEST); @@ -900,7 +894,7 @@ public void shouldReturn200WhenPackagePostIsValid() throws URISyntaxException, I 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)) + verify(1, postRequestedFor(urlPathEqualTo(PACKAGES_STUB_URL)) .withRequestBody(equalToJson(readFile(packagePostRmApiRequestFile), false, true))); } @@ -914,7 +908,7 @@ public void shouldReturn200OnPostPackageWithExistedAccessType() throws URISyntax 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)) + verify(1, postRequestedFor(urlPathEqualTo(PACKAGES_STUB_URL)) .withRequestBody(equalToJson(readFile(packagePostRmApiRequestFile), false, true))); List<AccessTypeMapping> accessTypeMappingsInDb = getAccessTypeMappings(vertx); @@ -957,7 +951,7 @@ public void shouldReturn400WhenPackagePostDataIsInvalid() throws URISyntaxExcept 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), + mockPost(new EqualToPattern(LISTS_STUB_URL), equalToJson(""" { "contentType" : 1, @@ -1143,7 +1137,7 @@ public void shouldReturn400OnGetWithResourcesWhenRmApi400() throws IOException, stubFor( get( new UrlPathPattern(new RegexPattern( - PACKAGE_BY_ID_URL + "/titles.*"), + LIST_BY_ID_STUB_URL + "/titles.*"), true)) .willReturn(new ResponseDefinitionBuilder() .withBody(readFile(stubResponseFile)) @@ -1177,14 +1171,14 @@ public void shouldReturnUnauthorizedOnGetWithResourcesWhenRmApi403() { @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); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), PACKAGE_STUB_FILE); + mockGet(new RegexPattern(LIST_BY_ID_2_STUB_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); + actualResponse, true); } @Test @@ -1200,12 +1194,12 @@ public void shouldReturn422OnFetchPackagesInBulkWithInvalidIdFormat() throws IOE @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); + mockGet(new RegexPattern(LIST_BY_ID_STUB_URL), PACKAGE_STUB_FILE); + mockGet(new RegexPattern(LIST_BY_ID_2_STUB_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)) + get(new UrlPathPattern(new EqualToPattern(LISTS_STUB_URL + "/9999999"), false)) .willReturn(new ResponseDefinitionBuilder() .withBody(readFile(notFoundResponse)) .withStatus(404))); @@ -1288,7 +1282,7 @@ private void mockUpdateScenario(String initialPackage, String updatedPackage) { mockUpdateScenario(initialPackage); stubFor( - get(PACKAGE_URL_PATTERN) + get(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .inScenario(GET_PACKAGE_SCENARIO) .whenScenarioStateIs(PACKAGE_UPDATED_STATE) .willReturn(new ResponseDefinitionBuilder() @@ -1297,13 +1291,13 @@ private void mockUpdateScenario(String initialPackage, String updatedPackage) { private void mockUpdateScenario(String initialPackage) { stubFor( - get(PACKAGE_URL_PATTERN) + get(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .inScenario(GET_PACKAGE_SCENARIO) .willReturn(new ResponseDefinitionBuilder() .withBody(initialPackage))); stubFor( - put(PACKAGE_URL_PATTERN) + put(urlPathEqualTo(LIST_BY_ID_STUB_URL)) .inScenario(GET_PACKAGE_SCENARIO) .willReturn(new ResponseDefinitionBuilder() .withStatus(SC_NO_CONTENT)) @@ -1338,7 +1332,7 @@ private ExtractableResponse<Response> sendPost(String requestBody) throws IOExce 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); + mockGet(new EqualToPattern(LIST_BY_ID_STUB_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/util/PackagesTestUtil.java b/src/test/java/org/folio/util/PackagesTestUtil.java index 21e203c0f..5946b71a9 100644 --- a/src/test/java/org/folio/util/PackagesTestUtil.java +++ b/src/test/java/org/folio/util/PackagesTestUtil.java @@ -95,7 +95,7 @@ public static void setUpPackage(Vertx vertx, String credentialsId, String packag public static void mockPackageWithName(String stubPackageId, String stubProviderId, String stubPackageName) throws IOException, URISyntaxException { - mockGetWithBody(new RegexPattern(".*vendors/" + stubProviderId + "/packages/" + stubPackageId), + mockGetWithBody(new RegexPattern(".*lists/" + stubPackageId), getPackageResponse(stubPackageName, stubPackageId, stubProviderId)); } 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 1532dd3ff..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,22 +1,28 @@ { + "packageName": "name of the ages forever and ever", "contentType": 8, "isSelected": true, - "customAltNames": [ + "visibility": [ { - "id": 1234, - "altName": "Name of the ages (custom name)" - }, - { - "altName": "Another custom name" + "category": "PF", + "hidden": true, + "reason": "Hidden by customer" } ], - "customDisplayName": "Name of The Ages (2026)", + "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, - "isFreeAccess": 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/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..de2576c89 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,83 @@ { - "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 + } + ] }, - "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..e68df6c35 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,49 +1,102 @@ { - "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" : "" + "data": [ + { + "id": "392-3007", + "type": "packages", + "attributes": { + "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, + "isFreeAccess": false, + "isPrimaryPackage": true, + "isSelected": false, + "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", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "isCustom": false, + "isSelected": false, "name": "American Academy of Orthopaedic Surgeons", "packageId": 1597443, - "isCustom": false, + "packageType": "Variable", "providerId": 114569, "providerName": "American Academy of Orthopaedic Surgeons", - "titleCount": 108, - "isSelected": false, "selectedCount": 0, - "packageType": "Variable", - "contentType": "Aggregated Full Text", - "customCoverage": { - "beginCoverage": "", - "endCoverage": "" + "titleCount": 108, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + }, + { + "category": "MARC", + "hidden": true + } + ] + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } }, - "visibilityData": { - "isHidden": false, - "reason": "" + "provider": { + "meta": { + "included": false + } } } }, @@ -51,23 +104,47 @@ "id": "554-3943", "type": "packages", "attributes": { + "contentType": "E-Journal", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "isCustom": false, + "isSelected": false, "name": "American Academy of Pediatrics (AAP)", "packageId": 3943, - "isCustom": false, + "packageType": "Variable", "providerId": 554, "providerName": "American Academy of Pediatrics (AAP)", - "titleCount": 6, - "isSelected": false, "selectedCount": 0, - "packageType": "Variable", - "contentType": "E-Journal", - "customCoverage": { - "beginCoverage": "", - "endCoverage": "" + "titleCount": 6, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + }, + { + "category": "FTF", + "hidden": true + }, + { + "category": "MARC", + "hidden": true + } + ] + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } }, - "visibilityData": { - "isHidden": false, - "reason": "" + "provider": { + "meta": { + "included": false + } } } }, @@ -75,23 +152,38 @@ "id": "554-7566", "type": "packages", "attributes": { + "contentType": "E-Book", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "isCustom": false, + "isSelected": false, "name": "American Academy of Pediatrics (AAP) eBooks", "packageId": 7566, - "isCustom": false, + "packageType": "Variable", "providerId": 554, "providerName": "American Academy of Pediatrics (AAP)", - "titleCount": 207, - "isSelected": false, "selectedCount": 0, - "packageType": "Variable", - "contentType": "E-Book", - "customCoverage": { - "beginCoverage": "", - "endCoverage": "" + "titleCount": 207, + "visibility": [ + { + "category": "FTF", + "hidden": false + } + ] + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } }, - "visibilityData": { - "isHidden": false, - "reason": "" + "provider": { + "meta": { + "included": false + } } } }, @@ -99,31 +191,47 @@ "id": "554-19236", "type": "packages", "attributes": { + "contentType": "E-Journal", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "isCustom": false, + "isSelected": false, "name": "American Academy of Pediatrics (KMLA)", "packageId": 19236, - "isCustom": false, + "packageType": "Complete", "providerId": 554, "providerName": "American Academy of Pediatrics (AAP)", - "titleCount": 6, - "isSelected": false, "selectedCount": 0, - "packageType": "Complete", - "contentType": "E-Journal", - "customCoverage": { - "beginCoverage": "", - "endCoverage": "" + "titleCount": 6, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ] + }, + "relationships": { + "resources": { + "data": [], + "meta": { + "included": false + } }, - "visibilityData": { - "isHidden": false, - "reason": "" + "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.json b/src/test/resources/responses/kb-ebsco/packages/expected-package-collection-with-one-element.json index 0fef6d07e..ddc0d4246 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,49 @@ { - "data" : [ { - "id" : "19-3964", - "type" : "packages", - "attributes" : { - "contentType" : "Online Reference", - "customCoverage" : { - "beginCoverage" : "", - "endCoverage" : "" + "data": [ + { + "id": "19-null", + "type": "packages", + "attributes": { + "contentType": "Online Reference", + "customCoverage": { + "beginCoverage": "", + "endCoverage": "" + }, + "isCustom": true, + "isSelected": true, + "name": "TEST_PACKAGE_NAME", + "packageType": "Custom", + "providerId": 19, + "providerName": "TEST_VENDOR_NAME", + "selectedCount": 5, + "titleCount": 5, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ] }, - "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 - } - }, - "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/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..7f319478e 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 @@ -6,10 +6,13 @@ "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..28ef06a5e 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 @@ -9,10 +9,13 @@ "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 b6ba86df1..76faeaa8c 100644 --- a/src/test/resources/responses/rmapi/packages/get-packages-response.json +++ b/src/test/resources/responses/rmapi/packages/get-packages-response.json @@ -4,15 +4,40 @@ { "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", @@ -40,10 +65,17 @@ "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", @@ -61,10 +93,21 @@ "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", @@ -82,10 +125,12 @@ "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", @@ -103,10 +148,13 @@ "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 From 925287466df7056676552e2e26c60718e4f66f44 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Mon, 22 Jun 2026 10:54:53 +0300 Subject: [PATCH 08/16] fix tests --- .../validator/PackagePutBodyValidator.java | 2 +- .../folio/rest/validator/ValidatorUtil.java | 9 ++ .../org/folio/rest/impl/WireMockTestBase.java | 13 ++- .../EholdingsPackagesTest.java | 2 +- .../EholdingsProvidersImplTest.java | 8 +- .../EholdingsResourcesImplTest.java | 9 +- .../PackagePutBodyValidatorTest.java | 7 +- .../folio/rmapi/PackageServiceImplTest.java | 4 +- ...collection-with-one-element-with-tags.json | 88 ++++++++++--------- ...d-package-collection-with-one-element.json | 2 +- ...ected-resource-by-id-with-all-objects.json | 25 +++--- .../expected-resource-by-id-with-package.json | 25 +++--- .../get-package-by-id-for-resource.json | 2 +- .../packages/get-packages-by-provider-id.json | 2 +- 14 files changed, 117 insertions(+), 81 deletions(-) diff --git a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java b/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java index 718884207..3f06a4121 100644 --- a/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java +++ b/src/main/java/org/folio/rest/validator/PackagePutBodyValidator.java @@ -42,7 +42,7 @@ private void validateNotSelected(PackagePutDataAttributes attributes, Boolean al Boolean isSelected = attributes.getIsSelected(); if (isSelected == null || !isSelected) { ValidatorUtil.checkFalseOrNull("allowKbToAddTitles", allowKbToAddTitles); - ValidatorUtil.checkIsNull("visibility", visibility); + 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/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/test/java/org/folio/rest/impl/WireMockTestBase.java b/src/test/java/org/folio/rest/impl/WireMockTestBase.java index 4aed57ac9..cc61e1a3a 100644 --- a/src/test/java/org/folio/rest/impl/WireMockTestBase.java +++ b/src/test/java/org/folio/rest/impl/WireMockTestBase.java @@ -15,12 +15,15 @@ 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.STUB_TENANT; 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.builder.RequestSpecBuilder; +import io.restassured.filter.log.LogDetail; import io.restassured.http.Header; import io.restassured.http.Headers; import io.restassured.response.ExtractableResponse; @@ -203,8 +206,16 @@ protected ExtractableResponse<Response> deleteWithStatus(String resourcePath, in } protected void checkResponseNotEmptyWhenStatusIs400(String path) { + var specification = new RequestSpecBuilder() + .addHeader(XOkapiHeaders.TENANT, STUB_TENANT) + .addHeader(XOkapiHeaders.USER_ID, JOHN_ID) + .addHeader(XOkapiHeaders.URL, getWiremockUrl()) + .setBaseUri(host + ":" + port) + .setPort(port) + .log(LogDetail.ALL) + .build(); RestAssured.given() - .spec(getRequestSpecification()) + .spec(specification) .when() .get(path) .then() diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java index 11ee2b500..1038be3c2 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java @@ -1137,7 +1137,7 @@ public void shouldReturn400OnGetWithResourcesWhenRmApi400() throws IOException, stubFor( get( new UrlPathPattern(new RegexPattern( - LIST_BY_ID_STUB_URL + "/titles.*"), + PACKAGE_BY_ID_URL + "/titles.*"), true)) .willReturn(new ResponseDefinitionBuilder() .withBody(readFile(stubResponseFile)) diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java index f471488f9..ef69026ac 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java @@ -117,7 +117,7 @@ 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.*"; + "/rm/rmaccounts/v2/.*" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/lists.*"; private static final UrlPathPattern PROVIDER_URL_PATTERN = new UrlPathPattern(new RegexPattern(PROVIDER_RM_API_PATH), true); @@ -264,7 +264,7 @@ public void shouldReturnEmptyResponseWhenPackagesReturnedWithErrorOnSearchByAcce 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); + mockGet(new RegexPattern(".*/lists/.*"), 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); @@ -516,7 +516,7 @@ public void shouldReturnProviderPackagesWithTags() throws IOException, URISyntax @Test public void shouldReturn400IfProviderIdInvalid() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/invalid/packages"); + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/invalid/lists"); } @Test @@ -554,7 +554,7 @@ public void shouldReturn400IfQueryParamInvalid() { @Test public void shouldReturn404WhenNonProviderIdNotFound() { - String rmapiInvalidProviderIdUrl = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/191919/packages"; + String rmapiInvalidProviderIdUrl = ".*" + STUB_CUSTOMER_ID + "/vendors/191919/lists"; mockGet(new RegexPattern(rmapiInvalidProviderIdUrl), SC_NOT_FOUND); diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java index 4c24f158d..59a6041da 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java @@ -94,8 +94,10 @@ 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; + "/rm/rmaccounts/v2/" + STUB_CUSTOMER_ID + "/lists/" + STUB_PACKAGE_ID; + private static final String MANAGED_RESOURCE_ENDPOINT = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + + STUB_VENDOR_ID + "/packages/" + STUB_PACKAGE_ID + + "/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; @@ -627,7 +629,8 @@ public void shouldReturnErrorWhenRmApiFails() throws IOException, URISyntaxExcep } private void mockPackageResources(String stubPackageResourcesFile) throws IOException, URISyntaxException { - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), stubPackageResourcesFile); + mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + + "/packages/" + STUB_PACKAGE_ID + "/titles.*"), stubPackageResourcesFile); } private void mockPackage(String responseFile) throws IOException, URISyntaxException { diff --git a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java b/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java index 6808ae8eb..8052f7eba 100644 --- a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java @@ -4,11 +4,13 @@ import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThrows; +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.junit.Test; @@ -34,12 +36,11 @@ public void shouldThrowExceptionWhenPackageIsNotSelectedAndIsHiddenIsTrue() { var request = PackagesTestData.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")); + assertThat(exception.getMessage(), containsString("visibility")); } @Test diff --git a/src/test/java/org/folio/rmapi/PackageServiceImplTest.java b/src/test/java/org/folio/rmapi/PackageServiceImplTest.java index 223c684d0..fb9d53e5b 100644 --- a/src/test/java/org/folio/rmapi/PackageServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/PackageServiceImplTest.java @@ -37,7 +37,7 @@ public class PackageServiceImplTest { @Test public void shouldReturnCachedPackage() throws IOException, URISyntaxException { RegexPattern getPackagePattern = new RegexPattern( - "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages/" + STUB_PACKAGE_ID); + "/rm/rmaccounts/v2/" + STUB_CUSTOMER_ID + "/lists/" + STUB_PACKAGE_ID); Configuration configuration = Configuration.builder() .url("http://127.0.0.1:" + userMockServer.port()) @@ -49,7 +49,7 @@ public void shouldReturnCachedPackage() throws IOException, URISyntaxException { mockGet(getPackagePattern, CUSTOM_PACKAGE_STUB_FILE); - var packageId = new PackageId(STUB_PACKAGE_ID, STUB_VENDOR_ID); + var packageId = new PackageId(STUB_VENDOR_ID, STUB_PACKAGE_ID); service.retrievePackage(packageId, Collections.emptyList(), true).join(); service.retrievePackage(packageId, Collections.emptyList(), true).join(); 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 ddc0d4246..b015269c6 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,7 +1,7 @@ { "data": [ { - "id": "19-null", + "id": "19-3964", "type": "packages", "attributes": { "contentType": "Online Reference", 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..87633804e 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,17 +199,19 @@ "packageType": "Variable", "providerId": 19, "providerName": "ABC-CLIO", - "selectedCount": 9590, - "titleCount": 9590, - "visibilityData": { - "isHidden": true, - "reason": "" - }, - "allowKbToAddTitles": false, "proxy": { "id": "Proxy-ID-123", "inherited": true - } + }, + "selectedCount": 9590, + "titleCount": 9590, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ] }, "relationships": { "resources": { @@ -228,4 +231,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..c7a05bbaa 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,17 +122,19 @@ "packageType": "Variable", "providerId": 19, "providerName": "ABC-CLIO", - "selectedCount": 9590, - "titleCount": 9590, - "visibilityData": { - "isHidden": true, - "reason": "" - }, - "allowKbToAddTitles": false, "proxy": { "id": "Proxy-ID-123", "inherited": true - } + }, + "selectedCount": 9590, + "titleCount": 9590, + "visibility": [ + { + "category": "PF", + "reason": "Hidden by customer", + "hidden": false + } + ] }, "relationships": { "resources": { @@ -151,4 +154,4 @@ "jsonapi": { "version": "1.0" } -} +} \ No newline at end of file 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 7f319478e..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,5 +1,5 @@ { - "packageId": 3964, + "listId": 3964, "packageName": "ABC-CLIO eBook Collection", "isCustom": false, "vendorId": 19, 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 28ef06a5e..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,7 +2,7 @@ "totalResults": 1, "packagesList": [ { - "packageId": 3964, + "listId": 3964, "packageName": "TEST_PACKAGE_NAME", "isCustom": true, "vendorId": 19, From 8bcba0296df10d52406755e1ace01a895f0e7331 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Mon, 22 Jun 2026 11:16:37 +0300 Subject: [PATCH 09/16] fix tests2 --- .../java/org/folio/rest/impl/EholdingsProvidersImpl.java | 2 ++ .../integrationsuite/EholdingsResourcesImplTest.java | 9 ++++++--- .../expected-package-collection-with-one-element.json | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index b3682fc7b..adf7073fa 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -191,6 +191,8 @@ tags, new RequestContext(headers).getTenant()) @SuppressWarnings("checkstyle:MethodLength") @Override + @Validate + @HandleValidationErrors public void getEholdingsProvidersPackagesByProviderId(String providerId, String q, String queryField, String queryType, boolean highlight, List<String> filterTags, List<String> filterAccessType, String filterSelected, diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java index 59a6041da..650646b7d 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java @@ -218,7 +218,8 @@ public void shouldReturn404WhenRmApiNotFoundOnResourceGet() throws IOException, String stubResponseFile = "responses/rmapi/resources/get-resource-by-id-not-found-response.json"; stubFor( - get(new UrlPathPattern(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), true)) + get(new UrlPathPattern(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + + "/packages/" + STUB_PACKAGE_ID + "/titles.*"), true)) .willReturn(new ResponseDefinitionBuilder() .withBody(readFile(stubResponseFile)) .withStatus(404))); @@ -251,7 +252,8 @@ public void shouldReturn400WhenValidationErrorOnResourceGet() { @Test public void shouldReturn500WhenRmApiReturns500ErrorOnResourceGet() { - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), SC_INTERNAL_SERVER_ERROR); + mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + + "/packages/" + STUB_PACKAGE_ID + "/titles.*"), SC_INTERNAL_SERVER_ERROR); JsonapiError error = getWithStatus(STUB_MANAGED_RESOURCE_PATH, SC_INTERNAL_SERVER_ERROR, STUB_USER_ID_HEADER).as(JsonapiError.class); @@ -617,7 +619,8 @@ public void shouldReturnResourcesAndFailedIds() throws IOException, URISyntaxExc @Test public void shouldReturnErrorWhenRmApiFails() throws IOException, URISyntaxException { - mockGet(new RegexPattern(MANAGED_PACKAGE_ENDPOINT + "/titles.*"), SC_INTERNAL_SERVER_ERROR); + mockGet(new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + + "/packages/" + STUB_PACKAGE_ID + "/titles.*"), SC_INTERNAL_SERVER_ERROR); String postBody = readFile("requests/kb-ebsco/resource/post-resources-bulk.json"); final ResourceBulkFetchCollection bulkFetchCollection = postWithOk(RESOURCES_BULK_FETCH, postBody, 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 b015269c6..9a17870c7 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 @@ -12,6 +12,7 @@ "isCustom": true, "isSelected": true, "name": "TEST_PACKAGE_NAME", + "packageId": 3964, "packageType": "Custom", "providerId": 19, "providerName": "TEST_VENDOR_NAME", From cf504066471ef8ea75d4c2b5f853c5c3270792f6 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Mon, 22 Jun 2026 11:41:29 +0300 Subject: [PATCH 10/16] fix tests3 --- .../org/folio/rest/impl/EholdingsProvidersImpl.java | 12 +++++++++--- .../EholdingsProvidersImplTest.java | 4 ++-- .../providers/expected-provider-with-packages.json | 13 ++++++++----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index adf7073fa..89ad0a86c 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -128,6 +128,7 @@ public void getEholdingsProviders(String q, List<String> filterTags, String sort } @Override + @Validate @HandleValidationErrors public void getEholdingsProvidersByProviderId(String providerId, String include, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, @@ -145,6 +146,7 @@ public void getEholdingsProvidersByProviderId(String providerId, String include, } @Override + @Validate @HandleValidationErrors public void putEholdingsProvidersByProviderId(String providerId, String contentType, ProviderPutRequest entity, Map<String, String> okapiHeaders, @@ -162,6 +164,8 @@ public void putEholdingsProvidersByProviderId(String providerId, String contentT } @Override + @Validate + @HandleValidationErrors public void putEholdingsProvidersTagsByProviderId(String providerId, String contentType, ProviderTagsPutRequest entity, Map<String, String> headers, @@ -201,6 +205,7 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { + var parsedProviderId = parseProviderId(providerId); var filter = PackageRecordFilter.builder() .query(q) .queryField(queryField) @@ -226,7 +231,7 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String .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 -> @@ -235,12 +240,13 @@ public void getEholdingsProvidersPackagesByProviderId(String providerId, String .executeWithResult(PackageCollection.class); } - private Function<RmApiTemplateContext, CompletableFuture<?>> retrieveFilteredPackages(PackageRecordFilter filter) { + private Function<RmApiTemplateContext, CompletableFuture<?>> retrieveFilteredPackages(int providerId, + PackageRecordFilter filter) { var packageFilter = filter.toClientFilter(searchProperties); var pageable = filter.toPageable(); return context -> context.getPackagesService() - .retrievePackages(filter.parseProviderId(), packageFilter, pageable) + .retrievePackages(providerId, packageFilter, pageable) .thenCompose(packages -> loadTags(packages, context)); } diff --git a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java index ef69026ac..ed0b4664f 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java +++ b/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java @@ -322,7 +322,7 @@ public void shouldReturnProvidersOnGetWithPackages() throws IOException, URISynt stubFor( get(new UrlPathPattern( - new RegexPattern("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/packages.*"), true)) + new RegexPattern("/rm/rmaccounts/v2/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/lists.*"), true)) .willReturn(new ResponseDefinitionBuilder() .withBody(readFile(STUB_PACKAGE_RESPONSE)))); @@ -516,7 +516,7 @@ public void shouldReturnProviderPackagesWithTags() throws IOException, URISyntax @Test public void shouldReturn400IfProviderIdInvalid() { - checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/invalid/lists"); + checkResponseNotEmptyWhenStatusIs400(PROVIDER_PATH + "/invalid/packages"); } @Test 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 From 3e128e4d3d5424c317741ddda7471326018c38fb Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Mon, 22 Jun 2026 11:45:45 +0300 Subject: [PATCH 11/16] fix tests4 --- src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java index 89ad0a86c..b6538ee62 100644 --- a/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java +++ b/src/main/java/org/folio/rest/impl/EholdingsProvidersImpl.java @@ -133,10 +133,10 @@ public void getEholdingsProviders(String q, List<String> filterTags, String sort public void getEholdingsProvidersByProviderId(String providerId, String include, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) { - + var parseProviderId = parseProviderId(providerId); templateFactory.createTemplate(okapiHeaders, asyncResultHandler) .requestAction(context -> - context.getProvidersService().retrieveProvider(parseProviderId(providerId), include) + context.getProvidersService().retrieveProvider(parseProviderId, include) .thenCompose(result -> loadTags(result, context)) ) .addErrorMapper(ResourceNotFoundException.class, exception -> From d36b202665b8e9db7b10838505fd19184496ebbc Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 26 Jun 2026 12:48:54 +0300 Subject: [PATCH 12/16] migrate to junit6 --- pom.xml | 103 +- .../costperuse/TitleCostPerUseConverter.java | 15 +- .../org/folio/rmapi/TitlesServiceImpl.java | 8 +- .../accesstypes/AccessTypesServiceImpl.java | 11 +- .../AssignedUsersServiceImpl.java | 8 +- .../service/users/UsersLookUpService.java | 46 +- .../java/org/folio/common/LogUtilsTest.java | 10 +- .../packages/PackageRepositoryImplTest.java | 41 +- .../providers/ProviderRepositoryImplTest.java | 23 +- .../ResourcesRepositoryImplTest.java | 30 +- .../repository/tag/TagRepositoryImplTest.java | 39 +- .../titles/TitleRepositoryImplTest.java | 31 +- .../AccessTypeCollectionConverterTest.java | 17 +- .../attr/EmbargoPeriodConverterTest.java | 99 +- .../PackageTitleCostPerUseConverterTest.java | 34 +- .../HoldingsCollectionItemConverterTest.java | 46 +- ...ialsNotSecuredCollectionConverterTest.java | 66 +- .../KbCredentialsNotSecuredConverterTest.java | 54 +- ...entialsSecuredCollectionConverterTest.java | 66 +- .../KbCredentialsSecuredConverterTest.java | 54 +- .../CustomLabelsCollectionConverterTest.java | 24 +- .../CustomLabelsItemCollectionTest.java | 21 +- .../packages/PackageRequestConverterTest.java | 117 +- .../PackageResponseConverterTest.java | 48 +- .../ResourceRequestConverterTest.java | 230 ++- .../titles/TitleCollectionConverterTest.java | 30 +- .../titles/TitlePutRequestConverterTest.java | 103 +- ...efaultLoadHoldingsImplIntegrationTest.java | 476 ++++++ ...faultLoadServiceFacadeIntegrationTest.java | 126 ++ ...ldingsAccessTypesImplIntegrationTest.java} | 194 +-- ...dingsAssignedUsersImplIntegrationTest.java | 196 +++ ...holdingsCostperuseImplIntegrationTest.java | 694 +++++++++ ...holdingsCurrenciesImplIntegrationTest.java | 41 + ...ldingsCustomLabelsImplIntegrationTest.java | 183 +++ .../EholdingsExportImplIntegrationTest.java | 198 +++ ...dingsKbCredentialsImplIntegrationTest.java | 651 ++++++++ .../EholdingsPackagesIntegrationTest.java | 1263 ++++++++++++++++ ...EholdingsProvidersImplIntegrationTest.java | 528 +++++++ ...holdingsProxyTypesImplIntegrationTest.java | 158 ++ ...EholdingsResourcesImplIntegrationTest.java | 622 ++++++++ ...EholdingsRootProxyImplIntegrationTest.java | 216 +++ .../impl/EholdingsStatusIntegrationTest.java | 90 ++ .../EholdingsTagsImplIntegrationTest.java | 201 +++ .../impl/EholdingsTitlesIntegrationTest.java | 543 +++++++ ...sageConsolidationImplIntegrationTest.java} | 181 +-- .../folio/rest/impl/IntegrationTestSuite.java | 65 - .../org/folio/rest/impl/PackagesTestData.java | 35 - .../folio/rest/impl/ProvidersTestData.java | 12 - .../folio/rest/impl/ResourcesTestData.java | 76 - .../org/folio/rest/impl/RmApiConstants.java | 26 - .../org/folio/rest/impl/TagsTestData.java | 7 - .../org/folio/rest/impl/TitlesTestData.java | 22 - ...actionLoadHoldingsImplIntegrationTest.java | 356 +++++ ...ctionLoadServiceFacadeIntegrationTest.java | 145 ++ ...idationCredentialsApiIntegrationTest.java} | 97 +- .../org/folio/rest/impl/WireMockTestBase.java | 267 ---- .../DefaultLoadHoldingsImplTest.java | 530 ------- .../DefaultLoadServiceFacadeTest.java | 139 -- .../EholdingsAssignedUsersImplTest.java | 280 ---- .../EholdingsCostperuseImplTest.java | 806 ---------- .../EholdingsCurrenciesImplTest.java | 45 - .../EholdingsCustomLabelsImplTest.java | 210 --- .../EholdingsExportImplTest.java | 272 ---- .../EholdingsKbCredentialsImplTest.java | 741 --------- .../EholdingsPackagesTest.java | 1340 ----------------- .../EholdingsProvidersImplTest.java | 600 -------- .../EholdingsProxyTypesImplTest.java | 162 -- .../EholdingsResourcesImplTest.java | 692 --------- .../EholdingsRootProxyImplTest.java | 233 --- .../integrationsuite/EholdingsStatusTest.java | 110 -- .../EholdingsTagsImplTest.java | 211 --- .../integrationsuite/EholdingsTitlesTest.java | 666 -------- .../LoadHoldingsStatusImplTest.java | 208 --- .../TransactionLoadHoldingsImplTest.java | 449 ------ .../TransactionLoadServiceFacadeTest.java | 194 --- .../impl/integrationsuite/package-info.java | 7 - .../org/folio/rest/util/IdParserTest.java | 25 +- .../AccessTypesBodyValidatorTest.java | 22 +- .../AssignedUsersBodyValidatorTest.java | 11 +- .../CustomLabelsPutBodyValidatorTest.java | 24 +- .../CustomPackagePutBodyValidatorTest.java | 29 +- .../validator/PackagePostValidatorTest.java | 105 +- .../PackagePutBodyValidatorTest.java | 65 +- .../PackageTagsPutBodyValidatorTest.java | 20 +- .../ProviderPutBodyValidatorTest.java | 18 +- .../validator/ResourcePostValidatorTest.java | 61 +- .../ResourcePutBodyValidatorTest.java | 56 +- .../validator/TitlePostBodyValidatorTest.java | 151 +- ...redentialsBodyAttributesValidatorTest.java | 28 +- .../folio/rmapi/PackageServiceImplTest.java | 53 +- .../folio/rmapi/ProviderServiceImplTest.java | 54 +- .../folio/rmapi/ResourceServiceImplTest.java | 60 +- .../org/folio/rmapi/TitleServiceImplTest.java | 72 +- .../AssignedUsersServiceImplTest.java | 33 +- .../export/LocaleSettingsServiceImplTest.java | 175 +-- .../AbstractLoadServiceFacadeTest.java | 21 +- .../DefaultLoadServiceFacadeTest.java | 17 +- ... => UcAuthServiceImplIntegrationTest.java} | 79 +- .../service/users/UsersLookUpServiceTest.java | 290 +--- .../org/folio/util/AccessTypesTestUtil.java | 28 +- .../java/org/folio/util/AssertTestUtil.java | 35 +- .../org/folio/util/AssignedUsersTestUtil.java | 4 +- .../util/HoldingsRetryStatusTestUtil.java | 4 +- .../util/HoldingsStatusAuditTestUtil.java | 4 +- .../org/folio/util/HoldingsStatusUtil.java | 12 +- .../java/org/folio/util/HoldingsTestUtil.java | 18 +- .../org/folio/util/IntegrationTestBase.java | 256 ++++ .../org/folio/util/KbCredentialsTestUtil.java | 108 +- .../java/org/folio/util/PackagesTestUtil.java | 68 +- .../org/folio/util/ProvidersTestUtil.java | 17 +- .../org/folio/util/ResourcesTestUtil.java | 20 +- .../java/org/folio/util/RmApiConstants.java | 160 ++ .../java/org/folio/util/TagsTestUtil.java | 41 +- .../folio/util/TestFutureFailedException.java | 13 + .../java/org/folio/util/TestSetUpHelper.java | 100 ++ .../folio/util/TestStartLoggingExtension.java | 22 + .../util/{KbTestUtil.java => TestUtil.java} | 82 +- .../java/org/folio/util/TitlesTestUtil.java | 35 +- .../java/org/folio/util/TokenTestUtils.java | 35 - .../org/folio/util/TransactionIdTestUtil.java | 4 +- .../org/folio/util/UcCredentialsTestUtil.java | 8 +- .../org/folio/util/UcSettingsTestUtil.java | 8 +- .../java/org/folio/util/WireMockTestBase.java | 295 ++++ .../expected-export-three-items-usd.txt | 6 +- .../status/get-status-in-progress.json | 5 - 125 files changed, 9234 insertions(+), 10561 deletions(-) create mode 100644 src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/DefaultLoadServiceFacadeIntegrationTest.java rename src/test/java/org/folio/rest/impl/{integrationsuite/EholdingsAccessTypesImplTest.java => EholdingsAccessTypesImplIntegrationTest.java} (66%) create mode 100644 src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsStatusIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java rename src/test/java/org/folio/rest/impl/{integrationsuite/EholdingsUsageConsolidationImplTest.java => EholdingsUsageConsolidationImplIntegrationTest.java} (63%) delete mode 100644 src/test/java/org/folio/rest/impl/IntegrationTestSuite.java delete mode 100644 src/test/java/org/folio/rest/impl/PackagesTestData.java delete mode 100644 src/test/java/org/folio/rest/impl/ProvidersTestData.java delete mode 100644 src/test/java/org/folio/rest/impl/ResourcesTestData.java delete mode 100644 src/test/java/org/folio/rest/impl/RmApiConstants.java delete mode 100644 src/test/java/org/folio/rest/impl/TagsTestData.java delete mode 100644 src/test/java/org/folio/rest/impl/TitlesTestData.java create mode 100644 src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java create mode 100644 src/test/java/org/folio/rest/impl/TransactionLoadServiceFacadeIntegrationTest.java rename src/test/java/org/folio/rest/impl/{integrationsuite/UsageConsolidationCredentialsApiTest.java => UsageConsolidationCredentialsApiIntegrationTest.java} (55%) delete mode 100644 src/test/java/org/folio/rest/impl/WireMockTestBase.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadHoldingsImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/DefaultLoadServiceFacadeTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAssignedUsersImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCostperuseImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCurrenciesImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsCustomLabelsImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsExportImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsKbCredentialsImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProvidersImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsProxyTypesImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsRootProxyImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsStatusTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTagsImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/EholdingsTitlesTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/LoadHoldingsStatusImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadHoldingsImplTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/TransactionLoadServiceFacadeTest.java delete mode 100644 src/test/java/org/folio/rest/impl/integrationsuite/package-info.java rename src/test/java/org/folio/service/uc/{UcAuthServiceImplTest.java => UcAuthServiceImplIntegrationTest.java} (53%) create mode 100644 src/test/java/org/folio/util/IntegrationTestBase.java create mode 100644 src/test/java/org/folio/util/RmApiConstants.java create mode 100644 src/test/java/org/folio/util/TestFutureFailedException.java create mode 100644 src/test/java/org/folio/util/TestSetUpHelper.java create mode 100644 src/test/java/org/folio/util/TestStartLoggingExtension.java rename src/test/java/org/folio/util/{KbTestUtil.java => TestUtil.java} (54%) delete mode 100644 src/test/java/org/folio/util/TokenTestUtils.java create mode 100644 src/test/java/org/folio/util/WireMockTestBase.java delete mode 100644 src/test/resources/responses/rmapi/holdings/status/get-status-in-progress.json diff --git a/pom.xml b/pom.xml index 37e302573..6c67b628c 100644 --- a/pom.xml +++ b/pom.xml @@ -61,11 +61,12 @@ <!-- Test dependencies versions --> <spring.version>7.0.7</spring.version> - <junit.version>4.13.2</junit.version> + <junit.version>6.1.0</junit.version> <rest-assured.version>6.0.0</rest-assured.version> <mockito.version>5.23.0</mockito.version> <assertj.version>3.27.7</assertj.version> <jsonassert.version>1.5.3</jsonassert.version> + <wiremock.version>3.13.2</wiremock.version> <easy-random-core.version>5.0.0</easy-random-core.version> <!-- Plugins versions --> @@ -88,24 +89,6 @@ <checkstyle.version>13.5.0</checkstyle.version> </properties> - <profiles> - <profile> - <id>default</id> - <activation> - <activeByDefault>true</activeByDefault> - </activation> - <properties> - <test.coverage.skip>false</test.coverage.skip> - </properties> - </profile> - <profile> - <id>no-coverage</id> - <properties> - <test.coverage.skip>true</test.coverage.skip> - </properties> - </profile> - </profiles> - <dependencyManagement> <dependencies> <dependency> @@ -129,6 +112,13 @@ <type>pom</type> <scope>import</scope> </dependency> + <dependency> + <groupId>org.junit</groupId> + <artifactId>junit-bom</artifactId> + <version>${junit.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> </dependencies> </dependencyManagement> @@ -240,22 +230,27 @@ </dependency> <!-- Test dependencies --> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>io.vertx</groupId> - <artifactId>vertx-unit</artifactId> + <artifactId>vertx-junit5</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>${junit.version}</version> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <version>${spring.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.folio</groupId> + <artifactId>postgres-testing</artifactId> + <version>${rmb.version}</version> <scope>test</scope> - <exclusions> - <exclusion> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest-core</artifactId> - </exclusion> - </exclusions> </dependency> <dependency> <groupId>io.rest-assured</groupId> @@ -275,6 +270,12 @@ <version>${mockito.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-junit-jupiter</artifactId> + <version>${mockito.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> @@ -288,37 +289,9 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.folio</groupId> - <artifactId>folio-service-tools-test</artifactId> - <version>${folio-service-tools.version}</version> - <exclusions> - <exclusion> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-engine</artifactId> - </exclusion> - <exclusion> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-api</artifactId> - </exclusion> - <exclusion> - <groupId>org.junit.platform</groupId> - <artifactId>junit-platform-engine</artifactId> - </exclusion> - <exclusion> - <groupId>org.junit.platform</groupId> - <artifactId>junit-platform-commons</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.logging.log4j</groupId> - <artifactId>log4j-slf4j2-impl</artifactId> - </exclusion> - </exclusions> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-test</artifactId> - <version>${spring.version}</version> + <groupId>org.wiremock</groupId> + <artifactId>wiremock</artifactId> + <version>${wiremock.version}</version> <scope>test</scope> </dependency> <dependency> @@ -686,15 +659,11 @@ <version>${maven-surefire-plugin.version}</version> <configuration> <useSystemClassLoader>false</useSystemClassLoader> - <excludes> - **/org/folio/rest/impl/integrationsuite/*.java - </excludes> <includes> <include>**/Test*.java</include> <include>**/*Test.java</include> <include>**/*Tests.java</include> <include>**/*TestCase.java</include> - <include>org/folio/rest/impl/IntegrationTestSuite.java</include> </includes> </configuration> </plugin> @@ -709,9 +678,6 @@ <goals> <goal>prepare-agent</goal> </goals> - <configuration> - <skip>${test.coverage.skip}</skip> - </configuration> </execution> <execution> <id>jacoco-coverage-report</id> @@ -719,9 +685,6 @@ <goals> <goal>report</goal> </goals> - <configuration> - <skip>${test.coverage.skip}</skip> - </configuration> </execution> </executions> </plugin> 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..f91445b90 100644 --- a/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java +++ b/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; +import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.math.NumberUtils; import org.folio.client.uc.model.UcCostAnalysis; import org.folio.holdingsiq.model.CoverageDates; @@ -28,6 +29,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; +@Log4j2 @Component public class TitleCostPerUseConverter implements Converter<TitleCostPerUseResult, TitleCostPerUse> { @@ -49,6 +51,7 @@ public TitleCostPerUse convert(TitleCostPerUseResult source) { var ucTitleCostPerUse = source.getUcTitleCostPerUse(); if (ucTitleCostPerUse.usage() == null || ucTitleCostPerUse.usage().platforms() == null) { + log.warn("No usage data for title {}", source.getTitleId()); return titleCostPerUse; } @@ -59,12 +62,12 @@ public TitleCostPerUse convert(TitleCostPerUseResult source) { Integer totalUsage = processPlatformUsages(source, specificPlatformUsages, usage); analysis.setHoldingsSummary(getHoldingsSummary(source, totalUsage)); - return titleCostPerUse - .withAttributes(new TitleCostPerUseDataAttributes() - .withUsage(usage) - .withAnalysis(analysis) - .withParameters(convertParameters(source.getConfiguration())) - ); + var attributes = new TitleCostPerUseDataAttributes() + .withUsage(usage) + .withAnalysis(analysis) + .withParameters(convertParameters(source.getConfiguration())); + log.info("Title cost per use: {}", attributes); + return titleCostPerUse.withAttributes(attributes); } private Integer processPlatformUsages(TitleCostPerUseResult source, diff --git a/src/main/java/org/folio/rmapi/TitlesServiceImpl.java b/src/main/java/org/folio/rmapi/TitlesServiceImpl.java index b811e704e..faec2420a 100644 --- a/src/main/java/org/folio/rmapi/TitlesServiceImpl.java +++ b/src/main/java/org/folio/rmapi/TitlesServiceImpl.java @@ -68,7 +68,13 @@ public void updateCache(Title title) { 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) { 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/users/UsersLookUpService.java b/src/main/java/org/folio/service/users/UsersLookUpService.java index 15e4a81e2..92ea81db5 100644 --- a/src/main/java/org/folio/service/users/UsersLookUpService.java +++ b/src/main/java/org/folio/service/users/UsersLookUpService.java @@ -24,7 +24,7 @@ import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHeaders; -import org.folio.common.OkapiParams; +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/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 bf44f529f..d57396995 100644 --- a/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java +++ b/src/test/java/org/folio/repository/providers/ProviderRepositoryImplTest.java @@ -1,32 +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 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(); var providerIds = repository.findIdsByTagFilter(filter, null, STUB_TENANT).join(); - assertThat(providerIds, empty()); + 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 512700ec1..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,47 +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.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( - // new PackagePutDataAttributes() - // .withIsSelected(true) - // .withVisibilityData(new VisibilityData() - // .withIsHidden(true)))); - // assertTrue(packagePut.getIsHidden()); - // } + @Test + void shouldCreateRequestToHidePackage() { + var packagePut = packagesConverter.convertToRmApiPackagePutRequest(getPackagePutRequest( + new PackagePutDataAttributes() + .withIsSelected(true) + .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))); @@ -49,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() @@ -61,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( - // new PackagePutDataAttributes() - // .withVisibilityData(new VisibilityData() - // .withIsHidden(true)))); - // assertTrue(packagePut.getIsHidden()); - // } + @Test + void shouldCreateRequestToChangeCustomPackageVisibility() { + var packagePut = + packagesConverter.convertToRmApiCustomPackagePutRequest(getPackagePutRequest( + new PackagePutDataAttributes() + .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..e4b922ec0 --- /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.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.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 66% 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..38ebc7637 100644 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsAccessTypesImplTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java @@ -1,9 +1,5 @@ -package org.folio.rest.impl.integrationsuite; +package org.folio.rest.impl; -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; @@ -13,9 +9,6 @@ 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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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..8e0dc55e5 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java @@ -0,0 +1,196 @@ +package org.folio.rest.impl; + +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.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_ENTITY).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_ENTITY).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..07804470d --- /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.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.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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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..70802a9a6 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java @@ -0,0 +1,41 @@ +package org.folio.rest.impl; + +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.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..e9bd920cc --- /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.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_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.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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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..26a39c753 --- /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.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.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.apache.http.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..ca092890e --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java @@ -0,0 +1,651 @@ +package org.folio.rest.impl; + +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_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.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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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..f74ea5c9e --- /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.apache.http.HttpStatus.SC_BAD_REQUEST; +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_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.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_ENTITY) + .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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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_ENTITY).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..8a60da889 --- /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.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.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_ENTITY).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_ENTITY).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..0d0662e77 --- /dev/null +++ b/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java @@ -0,0 +1,158 @@ +package org.folio.rest.impl; + +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.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..b79c46f4d --- /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.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.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_ENTITY, 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_ENTITY).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_ENTITY) + .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_ENTITY).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_ENTITY).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..35433096c --- /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.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.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..8e08d4fdf --- /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.apache.http.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..adcdab980 --- /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.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.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_ENTITY) + .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 63% 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..4993c3204 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; +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.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; 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_ENTITY) + .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_ENTITY) .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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_ENTITY) + .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..b62a88332 --- /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.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.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 55% 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..f83b1c072 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; +package org.folio.rest.impl; -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 com.github.tomakehurst.wiremock.client.WireMock.equalTo; 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.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 { +class UsageConsolidationCredentialsApiIntegrationTest extends IntegrationTestBase { - @Autowired - private UcAuthEbscoClient authEbscoClient; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - ReflectionTestUtils.setField(authEbscoClient, "baseUrl", getWiremockUrl()); - } - - @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,10 +68,10 @@ public void shouldSaveNewValidUcCredentials() { } @Test - public void shouldSaveNewInvalidUcCredentials() { + void shouldSaveNewInvalidUcCredentials() { mockAuthToken(SC_BAD_REQUEST); - String requestBody = getRequestBody(STUB_CLIENT_ID, STUB_CLIENT_SECRET); + var requestBody = getRequestBody(STUB_CLIENT_ID, STUB_CLIENT_SECRET); var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_ENTITY).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 requestBody = getRequestBody(newClientId, newClientSecret); var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_ENTITY).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 cc61e1a3a..000000000 --- a/src/test/java/org/folio/rest/impl/WireMockTestBase.java +++ /dev/null @@ -1,267 +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.STUB_TENANT; -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.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.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.PackageData; -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, Integer> vendorIdCache; - @Autowired - private VertxCache<PackageCacheKey, PackageData> 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) { - var specification = new RequestSpecBuilder() - .addHeader(XOkapiHeaders.TENANT, STUB_TENANT) - .addHeader(XOkapiHeaders.USER_ID, JOHN_ID) - .addHeader(XOkapiHeaders.URL, getWiremockUrl()) - .setBaseUri(host + ":" + port) - .setPort(port) - .log(LogDetail.ALL) - .build(); - RestAssured.given() - .spec(specification) - .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 1038be3c2..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsPackagesTest.java +++ /dev/null @@ -1,1340 +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.urlPathEqualTo; -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.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 String LISTS_STUB_URL = "/rm/rmaccounts/v2/" + STUB_CUSTOMER_ID + "/lists"; - private static final String LIST_BY_ID_STUB_URL = LISTS_STUB_URL + "/" + STUB_PACKAGE_ID; - private static final String LIST_BY_ID_2_STUB_URL = LISTS_STUB_URL + "/" + STUB_PACKAGE_ID_2; - private static final String RESOURCES_BY_PACKAGE_ID_URL = PACKAGE_BY_ID_URL + "/titles"; - 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/v2/" + STUB_CUSTOMER_ID + "/lists.*"), 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, true); - } - - @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(".*lists/.*"), 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(".*lists/.*"), 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/v2/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/lists.*"), - 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, true); - } - - @Test - public void shouldReturnPackagesOnGetById() throws IOException, URISyntaxException, JSONException { - mockGet(new RegexPattern(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); - - var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - mockPut(new EqualToPattern(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); - - var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - mockPut(new EqualToPattern(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); - mockPut(new EqualToPattern(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_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, true); - } - - @Test - public void shouldSendDeleteRequestForPackage() throws IOException, URISyntaxException { - var putBodyPattern = equalToJson("{\"isSelected\":false}", true, true); - - mockGet(new EqualToPattern(LIST_BY_ID_STUB_URL), CUSTOM_PACKAGE_STUB_FILE); - - mockPut(new EqualToPattern(LIST_BY_ID_STUB_URL), putBodyPattern, SC_NO_CONTENT); - - deleteWithNoContent(PACKAGES_PATH, STUB_USER_ID_HEADER); - - verify(1, putRequestedFor(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .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; - - PackageData packageData = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageData.class); - packageData = packageData.toBuilder().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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .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); - - 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()); - - 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); - - PackageData packageData = mapper - .readValue(getFile(CUSTOM_PACKAGE_STUB_FILE), PackageData.class) - .toBuilder() - .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(urlPathEqualTo(LIST_BY_ID_STUB_URL)).inScenario("Put package") - .whenScenarioStateIs(STARTED) - .willReturn(new ResponseDefinitionBuilder().withBody(readFile(CUSTOM_PACKAGE_STUB_FILE))) - .willSetStateTo("Not found")); - stubFor(get(urlPathEqualTo(LIST_BY_ID_STUB_URL)).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(LIST_BY_ID_STUB_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(urlPathEqualTo(LIST_BY_ID_STUB_URL))); - - assertErrorContainsTitle(error, "Invalid visibility"); - } - - @Test - public void shouldReturn422OnPutWhenCustomPackageUpdateLikeNotCustom() throws URISyntaxException, IOException { - String putBody = readFile("requests/kb-ebsco/package/put-package-selected.json"); - mockGet(new RegexPattern(LIST_BY_ID_STUB_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(urlPathEqualTo(LIST_BY_ID_STUB_URL))); - - assertErrorContainsTitle(error, "Package isCustom not matched"); - } - - @Test - public void shouldPassIsFullPackageAttributeToRmApi() throws URISyntaxException, IOException { - PackageData updatedPackage = mapper.readValue(getFile(PACKAGE_STUB_FILE), PackageData.class) - .toBuilder().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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), 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") - 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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), 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()); - - 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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), 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()); - - 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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .withRequestBody(equalToJson(readFile("requests/rmapi/packages/put-package-custom.json"), 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()); - - 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(LIST_BY_ID_STUB_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(LIST_BY_ID_STUB_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(urlPathEqualTo(PACKAGES_STUB_URL)) - .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(urlPathEqualTo(PACKAGES_STUB_URL)) - .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(LISTS_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(LIST_BY_ID_STUB_URL), PACKAGE_STUB_FILE); - mockGet(new RegexPattern(LIST_BY_ID_2_STUB_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, true); - } - - @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(LIST_BY_ID_STUB_URL), PACKAGE_STUB_FILE); - mockGet(new RegexPattern(LIST_BY_ID_2_STUB_URL), PACKAGE_2_STUB_FILE); - - String notFoundResponse = "responses/rmapi/packages/get-package-by-id-not-found-response.json"; - stubFor( - get(new UrlPathPattern(new EqualToPattern(LISTS_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 { - PackageData packageData = mapper.readValue(getFile(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 mapper.writeValueAsString(packageData); - } - - private String preparePackageData(boolean updatedSelected, String updatedBeginCoverage, String updatedEndCoverage, - boolean updatedAllowEbscoToAddTitles, boolean updatedHidden) - throws IOException, URISyntaxException { - PackageData packageData = mapper.readValue(getFile(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 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(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .inScenario(GET_PACKAGE_SCENARIO) - .whenScenarioStateIs(PACKAGE_UPDATED_STATE) - .willReturn(new ResponseDefinitionBuilder() - .withBody(updatedPackage))); - } - - private void mockUpdateScenario(String initialPackage) { - stubFor( - get(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .inScenario(GET_PACKAGE_SCENARIO) - .willReturn(new ResponseDefinitionBuilder() - .withBody(initialPackage))); - - stubFor( - put(urlPathEqualTo(LIST_BY_ID_STUB_URL)) - .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(LIST_BY_ID_STUB_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 ed0b4664f..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/v2/.*" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/lists.*"; - 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(".*/lists/.*"), 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/v2/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID + "/lists.*"), 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 = ".*" + STUB_CUSTOMER_ID + "/vendors/191919/lists"; - - 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 650646b7d..000000000 --- a/src/test/java/org/folio/rest/impl/integrationsuite/EholdingsResourcesImplTest.java +++ /dev/null @@ -1,692 +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/v2/" + STUB_CUSTOMER_ID + "/lists/" + STUB_PACKAGE_ID; - private static final String MANAGED_RESOURCE_ENDPOINT = "/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" - + STUB_VENDOR_ID + "/packages/" + STUB_PACKAGE_ID - + "/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("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID - + "/packages/" + STUB_PACKAGE_ID + "/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("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID - + "/packages/" + STUB_PACKAGE_ID + "/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("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID - + "/packages/" + STUB_PACKAGE_ID + "/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("/rm/rmaccounts/" + STUB_CUSTOMER_ID + "/vendors/" + STUB_VENDOR_ID - + "/packages/" + STUB_PACKAGE_ID + "/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 b6a6b7965..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.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 8052f7eba..9ca1eae0c 100644 --- a/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/PackagePutBodyValidatorTest.java @@ -1,111 +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.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) .withVisibility(List.of(new PackageVisibility().withCategory(PackageVisibility.Category.PF).withHidden(true))) ); var exception = assertThrows(InputValidationException.class, () -> validator.validate(request)); - assertThat(exception.getMessage(), containsString("visibility")); + 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 7f34c26e5..e829b6470 100644 --- a/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java +++ b/src/test/java/org/folio/rest/validator/ResourcePostValidatorTest.java @@ -1,5 +1,7 @@ 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.PackageData; @@ -9,9 +11,9 @@ 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() { + @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(); PackageData packageData = createPackage().build(); - validator.validateRelatedObjects( - packageData, - title, - titles); + assertThrows(InputValidationException.class, () -> + validator.validateRelatedObjects( + packageData, + title, + titles)); } private Titles.TitlesBuilder createTitles() { 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 fb9d53e5b..190a304e6 100644 --- a/src/test/java/org/folio/rmapi/PackageServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/PackageServiceImplTest.java @@ -1,58 +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/v2/" + STUB_CUSTOMER_ID + "/lists/" + 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)); - var packageId = new PackageId(STUB_VENDOR_ID, STUB_PACKAGE_ID); + 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 28b1621c6..ded17705b 100644 --- a/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java +++ b/src/test/java/org/folio/rmapi/ResourceServiceImplTest.java @@ -1,59 +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)); - var resourceId = new ResourceId(STUB_VENDOR_ID, STUB_PACKAGE_ID, STUB_TITLE_ID); + 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 b51233dbe..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.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 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()); + 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(requestContext); - - 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(requestContext); - - 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(requestContext); - - 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(requestContext); - - 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(requestContext); - - 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(requestContext); - - 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(requestContext); - - 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 f33c1c6cc..706200d00 100644 --- a/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java +++ b/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java @@ -1,20 +1,23 @@ package org.folio.service.holdings; import static org.folio.repository.holdings.LoadStatus.NONE; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import io.vertx.core.Vertx; import java.util.concurrent.CompletableFuture; import lombok.SneakyThrows; import org.folio.holdingsiq.service.impl.LoadServiceImpl; -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; -@RunWith(MockitoJUnitRunner.class) -public class DefaultLoadServiceFacadeTest { +@MockitoSettings(strictness = Strictness.WARN) +@ExtendWith(MockitoExtension.class) +class DefaultLoadServiceFacadeTest { @Mock private LoadServiceImpl loadService; @@ -26,7 +29,7 @@ public class DefaultLoadServiceFacadeTest { @Test @SneakyThrows - public void shouldNotFailOnEmptyStatusFromHoldingsIq() { + void shouldNotFailOnEmptyStatusFromHoldingsIq() { Mockito.when(loadService.getLoadingStatus()) .thenReturn(CompletableFuture.completedFuture(null)); diff --git a/src/test/java/org/folio/service/uc/UcAuthServiceImplTest.java b/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java similarity index 53% rename from src/test/java/org/folio/service/uc/UcAuthServiceImplTest.java rename to src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java index a109d16bc..555074713 100644 --- a/src/test/java/org/folio/service/uc/UcAuthServiceImplTest.java +++ b/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java @@ -3,20 +3,19 @@ import static io.vertx.core.Future.succeededFuture; import static org.apache.http.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..d44b81c9c --- /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.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.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.apache.http.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 5946b71a9..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.PackageData; +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 { - PackageData packageData = readJsonFile(STUB_PACKAGE_JSON_PATH, PackageData.class); - return Json.encode(packageData.toBuilder() - .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(".*lists/" + 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..13c2bf1bc --- /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.apache.http.HttpStatus.SC_FORBIDDEN; +import static org.apache.http.HttpStatus.SC_NOT_FOUND; +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; +import static org.folio.HttpStatus.SC_OK; +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/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/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 -} From b1d6b7895004c39a0e0456a59c22b7c302b01691 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 26 Jun 2026 12:58:14 +0300 Subject: [PATCH 13/16] fix test --- .../DefaultLoadServiceFacadeTest.java | 126 ++++++++---------- 1 file changed, 57 insertions(+), 69 deletions(-) diff --git a/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java b/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java index 1c5f9c118..ea1906ad2 100644 --- a/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java +++ b/src/test/java/org/folio/service/holdings/DefaultLoadServiceFacadeTest.java @@ -4,18 +4,22 @@ 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.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.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.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; @@ -24,18 +28,15 @@ @ExtendWith(MockitoExtension.class) class DefaultLoadServiceFacadeTest { - @Mock - private LoadServiceImpl loadService; - 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 @@ -48,29 +49,27 @@ public void setUp() { } @Test - @SneakyThrows void shouldNotFailOnEmptyStatusFromHoldingsIq() { - Mockito.when(loadService.getLoadingStatus()) + 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()); @@ -78,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()); @@ -98,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()); @@ -118,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()); @@ -190,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()); + } } From 0831e7403974a005878a3917ff79dfab9109f247 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 26 Jun 2026 14:14:20 +0300 Subject: [PATCH 14/16] add backward compability --- .../types/packages/packageDataAttributes.json | 5 + .../packages/packagePutDataAttributes.json | 5 + .../costperuse/TitleCostPerUseConverter.java | 14 +-- .../PackageCollectionItemConverter.java | 16 ++- .../packages/PackageRequestConverter.java | 14 ++- .../expected-package-by-id-with-provider.json | 6 +- ...package-collection-with-five-elements.json | 38 ++++++- ...d-package-collection-with-one-element.json | 6 +- .../get-created-package-response.json | 49 --------- ...ected-resource-by-id-with-all-objects.json | 6 +- .../expected-resource-by-id-with-package.json | 6 +- .../resources/expected-tagged-resources.json | 102 ------------------ 12 files changed, 95 insertions(+), 172 deletions(-) delete mode 100644 src/test/resources/responses/kb-ebsco/packages/get-created-package-response.json delete mode 100644 src/test/resources/responses/kb-ebsco/resources/expected-tagged-resources.json diff --git a/ramls/types/packages/packageDataAttributes.json b/ramls/types/packages/packageDataAttributes.json index 23276bc8d..2bbc171c2 100644 --- a/ramls/types/packages/packageDataAttributes.json +++ b/ramls/types/packages/packageDataAttributes.json @@ -142,6 +142,11 @@ "type": "object" }, "type": "array" + }, + "visibilityData": { + "type": "object", + "description": "Visibility data", + "$ref": "../visibilityData.json" } } } diff --git a/ramls/types/packages/packagePutDataAttributes.json b/ramls/types/packages/packagePutDataAttributes.json index 78eaa942f..90ef096cb 100644 --- a/ramls/types/packages/packagePutDataAttributes.json +++ b/ramls/types/packages/packagePutDataAttributes.json @@ -91,6 +91,11 @@ "type": "object" }, "type": "array" + }, + "visibilityData": { + "type": "object", + "description": "Visibility data", + "$ref": "../visibilityData.json" } } } 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 f91445b90..d50fc2793 100644 --- a/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java +++ b/src/main/java/org/folio/rest/converter/costperuse/TitleCostPerUseConverter.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Map; -import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.math.NumberUtils; import org.folio.client.uc.model.UcCostAnalysis; import org.folio.holdingsiq.model.CoverageDates; @@ -29,7 +28,6 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; -@Log4j2 @Component public class TitleCostPerUseConverter implements Converter<TitleCostPerUseResult, TitleCostPerUse> { @@ -51,7 +49,6 @@ public TitleCostPerUse convert(TitleCostPerUseResult source) { var ucTitleCostPerUse = source.getUcTitleCostPerUse(); if (ucTitleCostPerUse.usage() == null || ucTitleCostPerUse.usage().platforms() == null) { - log.warn("No usage data for title {}", source.getTitleId()); return titleCostPerUse; } @@ -62,12 +59,11 @@ public TitleCostPerUse convert(TitleCostPerUseResult source) { Integer totalUsage = processPlatformUsages(source, specificPlatformUsages, usage); analysis.setHoldingsSummary(getHoldingsSummary(source, totalUsage)); - var attributes = new TitleCostPerUseDataAttributes() - .withUsage(usage) - .withAnalysis(analysis) - .withParameters(convertParameters(source.getConfiguration())); - log.info("Title cost per use: {}", attributes); - return titleCostPerUse.withAttributes(attributes); + return titleCostPerUse + .withAttributes(new TitleCostPerUseDataAttributes() + .withUsage(usage) + .withAnalysis(analysis) + .withParameters(convertParameters(source.getConfiguration()))); } private Integer processPlatformUsages(TitleCostPerUseResult source, 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 8ae6abd12..041d59846 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageCollectionItemConverter.java @@ -13,6 +13,7 @@ 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; @@ -53,7 +54,20 @@ private PackageDataAttributes convertAttributes(PackageData packageData) { .withSelectedCount(packageData.getSelectedCount()) .withTitleCount(packageData.getTitleCount()) .withUrl(packageData.getPackageUrl()) - .withVisibility(mapItemsNullable(packageData.getVisibilityDetails(), this::convertVisibility)); + .withVisibility(mapItemsNullable(packageData.getVisibilityDetails(), this::convertVisibility)) + .withVisibilityData(convertVisibilityData(packageData)); + } + + private VisibilityData convertVisibilityData(PackageData packageData) { + 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) { 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 dd35cc5dd..9b01a2f86 100644 --- a/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java +++ b/src/main/java/org/folio/rest/converter/packages/PackageRequestConverter.java @@ -3,6 +3,7 @@ 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; @@ -11,6 +12,7 @@ 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 @@ -73,8 +75,16 @@ private PackagePut.PackagePutBuilder convertCommonAttributesToPackagePutRequest( builder.packageFreeAccess(attributes.getIsFreeAccess()); builder.packageUrl(attributes.getUrl()); - builder.visibilityDetails(mapItems(attributes.getVisibility(), - pv -> new Visibility(pv.getCategory().value(), pv.getHidden(), pv.getReason()))); + 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/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 de2576c89..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 @@ -37,7 +37,11 @@ "reason": "Hidden by customer", "hidden": false } - ] + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } }, "relationships": { "resources": { 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 e68df6c35..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 @@ -40,7 +40,11 @@ "reason": "Hidden by customer", "hidden": false } - ] + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } }, "relationships": { "resources": { @@ -61,12 +65,14 @@ "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", @@ -84,7 +90,11 @@ "category": "MARC", "hidden": true } - ] + ], + "visibilityData": { + "isHidden": true, + "reason": "" + } }, "relationships": { "resources": { @@ -105,12 +115,14 @@ "type": "packages", "attributes": { "contentType": "E-Journal", + "customAltNames": [], "customCoverage": { "beginCoverage": "", "endCoverage": "" }, "isCustom": false, "isSelected": false, + "managedAltNames": [], "name": "American Academy of Pediatrics (AAP)", "packageId": 3943, "packageType": "Variable", @@ -132,7 +144,11 @@ "category": "MARC", "hidden": true } - ] + ], + "visibilityData": { + "isHidden": true, + "reason": "" + } }, "relationships": { "resources": { @@ -153,12 +169,14 @@ "type": "packages", "attributes": { "contentType": "E-Book", + "customAltNames": [], "customCoverage": { "beginCoverage": "", "endCoverage": "" }, "isCustom": false, "isSelected": false, + "managedAltNames": [], "name": "American Academy of Pediatrics (AAP) eBooks", "packageId": 7566, "packageType": "Variable", @@ -171,7 +189,11 @@ "category": "FTF", "hidden": false } - ] + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } }, "relationships": { "resources": { @@ -192,12 +214,14 @@ "type": "packages", "attributes": { "contentType": "E-Journal", + "customAltNames": [], "customCoverage": { "beginCoverage": "", "endCoverage": "" }, "isCustom": false, "isSelected": false, + "managedAltNames": [], "name": "American Academy of Pediatrics (KMLA)", "packageId": 19236, "packageType": "Complete", @@ -211,7 +235,11 @@ "reason": "Hidden by customer", "hidden": false } - ] + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } }, "relationships": { "resources": { 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 9a17870c7..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 @@ -24,7 +24,11 @@ "reason": "Hidden by customer", "hidden": false } - ] + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } }, "relationships": { "resources": { 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/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 87633804e..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 @@ -211,7 +211,11 @@ "reason": "Hidden by customer", "hidden": false } - ] + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } }, "relationships": { "resources": { 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 c7a05bbaa..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 @@ -134,7 +134,11 @@ "reason": "Hidden by customer", "hidden": false } - ] + ], + "visibilityData": { + "isHidden": false, + "reason": "" + } }, "relationships": { "resources": { 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" - } -} From d2b07fecc2816b0c74e92b16f66402b93bd554ec Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 26 Jun 2026 14:32:22 +0300 Subject: [PATCH 15/16] fix deps --- pom.xml | 6 --- .../client/uc/UcApigeeEbscoClientImpl.java | 6 +-- .../rest/impl/EholdingsResourcesImpl.java | 6 +-- .../org/folio/rest/util/ExceptionMappers.java | 20 ++++----- .../rest/util/template/RmApiTemplate.java | 6 +-- .../service/users/UsersLookUpService.java | 2 +- ...efaultLoadHoldingsImplIntegrationTest.java | 6 +-- ...oldingsAccessTypesImplIntegrationTest.java | 20 ++++----- ...dingsAssignedUsersImplIntegrationTest.java | 10 ++--- ...holdingsCostperuseImplIntegrationTest.java | 24 +++++------ ...holdingsCurrenciesImplIntegrationTest.java | 2 +- ...ldingsCustomLabelsImplIntegrationTest.java | 16 +++---- .../EholdingsExportImplIntegrationTest.java | 8 ++-- ...dingsKbCredentialsImplIntegrationTest.java | 42 +++++++++---------- .../EholdingsPackagesIntegrationTest.java | 28 ++++++------- ...EholdingsProvidersImplIntegrationTest.java | 14 +++---- ...holdingsProxyTypesImplIntegrationTest.java | 8 ++-- ...EholdingsResourcesImplIntegrationTest.java | 20 ++++----- ...EholdingsRootProxyImplIntegrationTest.java | 12 +++--- .../EholdingsTagsImplIntegrationTest.java | 6 +-- .../impl/EholdingsTitlesIntegrationTest.java | 14 +++---- ...UsageConsolidationImplIntegrationTest.java | 20 ++++----- ...actionLoadHoldingsImplIntegrationTest.java | 4 +- ...lidationCredentialsApiIntegrationTest.java | 10 ++--- .../uc/UcAuthServiceImplIntegrationTest.java | 2 +- .../org/folio/util/IntegrationTestBase.java | 10 ++--- .../java/org/folio/util/WireMockTestBase.java | 6 +-- 27 files changed, 161 insertions(+), 167 deletions(-) diff --git a/pom.xml b/pom.xml index ea6d9b3eb..1ef2afe8f 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,6 @@ <commons-codec.version>1.22.0</commons-codec.version> <commons-beanutils.version>1.11.0</commons-beanutils.version> <lombok.version>1.18.46</lombok.version> - <httpcore.version>4.4.16</httpcore.version> <opencsv.version>5.12.0</opencsv.version> <commons-lang3.version>3.20.0</commons-lang3.version> @@ -185,11 +184,6 @@ <version>${lombok.version}</version> <scope>provided</scope> </dependency> - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpcore</artifactId> - <version>${httpcore.version}</version> - </dependency> <dependency> <groupId>org.folio</groupId> <artifactId>folio-di-support</artifactId> 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<UcMetricType> getUsageMetricType(UcConfiguration config private Completable<HttpResponse<Buffer>> handleResponse(Promise<HttpResponse<Buffer>> 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/rest/impl/EholdingsResourcesImpl.java b/src/main/java/org/folio/rest/impl/EholdingsResourcesImpl.java index 88bef6603..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,6 +31,7 @@ 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; @@ -368,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/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/template/RmApiTemplate.java b/src/main/java/org/folio/rest/util/template/RmApiTemplate.java index d923a2d0e..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,8 +9,8 @@ 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.HttpHeaders; +import org.folio.HttpStatus; import org.folio.holdingsiq.model.RequestContext; import org.folio.rest.util.ErrorHandler; import org.folio.rest.validator.HeaderValidator; @@ -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() ); diff --git a/src/main/java/org/folio/service/users/UsersLookUpService.java b/src/main/java/org/folio/service/users/UsersLookUpService.java index 92ea81db5..8abd3be4a 100644 --- a/src/main/java/org/folio/service/users/UsersLookUpService.java +++ b/src/main/java/org/folio/service/users/UsersLookUpService.java @@ -23,7 +23,7 @@ import javax.ws.rs.NotFoundException; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpHeaders; +import org.folio.HttpHeaders; import org.folio.holdingsiq.model.RequestContext; import org.folio.okapi.common.XOkapiHeaders; import org.folio.rest.util.RequestHeadersUtil; diff --git a/src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java index e4b922ec0..15e5f1b2e 100644 --- a/src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/DefaultLoadHoldingsImplIntegrationTest.java @@ -1,9 +1,9 @@ package org.folio.rest.impl; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -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.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; diff --git a/src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java index 38ebc7637..5ad279af7 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsAccessTypesImplIntegrationTest.java @@ -1,11 +1,11 @@ package org.folio.rest.impl; -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; +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; @@ -284,7 +284,7 @@ void shouldReturn400WhenPostAccessTypeWithDuplicateName() { String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); var error = - postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Duplicate name"); } @@ -306,7 +306,7 @@ void shouldReturn422WhenRequestHasUnrecognizedField() { .replaceFirst("type", "BadType"); String resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - String response = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY).asString(); + String response = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT).asString(); assertTrue(response.contains("Unrecognized field")); } @@ -317,7 +317,7 @@ void shouldReturn422WhenPostHasInvalidUuid() { String postBody = Json.encode(new AccessTypePostRequest().withData(accessType)); var resourcePath = String.format(KB_CREDENTIALS_ACCESS_TYPES_ENDPOINT, credentialsId); - var errors = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); + var errors = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals("data.id", errors.getErrors().getFirst().getParameters().getFirst().getKey()); } @@ -398,7 +398,7 @@ void shouldReturn422OnPutByCredentialsAndAccessTypeIdWhenInvalidId() { 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).as(Errors.class); + Errors errors = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals("data.id", errors.getErrors().getFirst().getParameters().getFirst().getKey()); } diff --git a/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java index 8e0dc55e5..d337a28ea 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsAssignedUsersImplIntegrationTest.java @@ -1,8 +1,8 @@ package org.folio.rest.impl; -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.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; @@ -126,7 +126,7 @@ void shouldReturn422OnPostWhenAssignedUserDoesNotHaveRequiredParameters() { var assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); var postBody = Json.encode(assignedUserPostRequest); - var errors = postWithStatus(assignedUserPath(credentialsId), postBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); + 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")))); @@ -143,7 +143,7 @@ void shouldReturn422OnPostWhenUserDoesNotExist() { var assignedUserPostRequest = new AssignedUserPostRequest().withData(expected); var postBody = Json.encode(assignedUserPostRequest); - var errors = postWithStatus(assignedUserPath(credentialsId), postBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); + var errors = postWithStatus(assignedUserPath(credentialsId), postBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals(1, errors.getErrors().size()); assertThat(errors.getErrors(), everyItem(hasProperty("additionalProperties", diff --git a/src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java index 07804470d..245b2ee6c 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsCostperuseImplIntegrationTest.java @@ -1,9 +1,9 @@ package org.folio.rest.impl; import static com.github.tomakehurst.wiremock.client.WireMock.matching; -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.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; @@ -155,7 +155,7 @@ void shouldReturnResourceCostPerUseWithEmptyNonPublisher() { void shouldReturn422OnGetResourceCpuWhenYearIsNull() { int titleId = 356; int packageId = 473; - var error = getWithStatus(resourceEndpoint(titleId, packageId, null, null), SC_UNPROCESSABLE_ENTITY) + var error = getWithStatus(resourceEndpoint(titleId, packageId, null, null), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid fiscalYear"); @@ -167,7 +167,7 @@ void shouldReturn422OnGetResourceCpuWhenPlatformIsInvalid() { int packageId = 473; String year = "2019"; String platform = "invalid"; - var error = getWithStatus(resourceEndpoint(titleId, packageId, year, platform), SC_UNPROCESSABLE_ENTITY) + var error = getWithStatus(resourceEndpoint(titleId, packageId, year, platform), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid platform"); @@ -254,7 +254,7 @@ void shouldReturnEmptyTitleCostPerUseWhenNoSelectedResources() { @Test void shouldReturn422OnGetTitleCpuWhenYearIsNull() { int titleId = 356; - var error = getWithStatus(titleEndpoint(titleId, null, null), SC_UNPROCESSABLE_ENTITY) + var error = getWithStatus(titleEndpoint(titleId, null, null), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid fiscalYear"); @@ -265,7 +265,7 @@ void shouldReturn422OnGetTitleCpuWhenPlatformIsInvalid() { int titleId = 356; String year = "2019"; String platform = "invalid"; - var error = getWithStatus(titleEndpoint(titleId, year, platform), SC_UNPROCESSABLE_ENTITY) + var error = getWithStatus(titleEndpoint(titleId, year, platform), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid platform"); @@ -308,7 +308,7 @@ void shouldReturnPackageCostPerUseWhenPackageCostIsEmpty() { @Test void shouldReturn422OnGetPackageCpuWhenYearIsNull() { int packageId = 222222; - var error = getWithStatus(packageEndpoint(packageId, null, null), SC_UNPROCESSABLE_ENTITY) + var error = getWithStatus(packageEndpoint(packageId, null, null), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid fiscalYear"); @@ -319,7 +319,7 @@ void shouldReturn422OnGetPackageCpuWhenPlatformIsInvalid() { int packageId = 222222; String year = "2019"; String platform = "invalid"; - var error = getWithStatus(packageEndpoint(packageId, year, platform), SC_UNPROCESSABLE_ENTITY) + var error = getWithStatus(packageEndpoint(packageId, year, platform), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid platform"); @@ -549,7 +549,7 @@ void shouldReturnResourcesCostPerUseCollectionSortedByNameWhenSortingByEqualsVal void shouldReturn422OnGetPackageResourcesCpuWhenYearIsNull() { int packageId = 222222; var error = - getWithStatus(packageResourcesEndpoint(packageId, null, null, null, null), SC_UNPROCESSABLE_ENTITY) + getWithStatus(packageResourcesEndpoint(packageId, null, null, null, null), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid fiscalYear"); @@ -561,7 +561,7 @@ void shouldReturn422OnGetPackageResourcesCpuWhenPlatformIsInvalid() { String year = "2019"; String platform = "invalid"; var error = - getWithStatus(packageResourcesEndpoint(packageId, year, platform, null, null), SC_UNPROCESSABLE_ENTITY) + getWithStatus(packageResourcesEndpoint(packageId, year, platform, null, null), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid platform"); @@ -575,7 +575,7 @@ void shouldReturn422OnGetPackageResourcesCpuWhenSortIsInvalid() { String sort = "invalid"; var error = getWithStatus(packageResourcesEndpoint(packageId, year, platform, null, null, sort, null), - SC_UNPROCESSABLE_ENTITY) + SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid sort"); diff --git a/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java index 70802a9a6..9235eedc7 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsCurrenciesImplIntegrationTest.java @@ -1,6 +1,6 @@ package org.folio.rest.impl; -import static org.apache.http.HttpStatus.SC_OK; +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; diff --git a/src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java index e9bd920cc..b06cbfd80 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsCustomLabelsImplIntegrationTest.java @@ -2,11 +2,11 @@ import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; -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_UNAUTHORIZED; -import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; +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; @@ -143,7 +143,7 @@ void shouldUpdateCustomLabelsOnPutWhenAllIsValidWithFiveItems() { 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_ENTITY) + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid Custom Label id"); @@ -154,7 +154,7 @@ void shouldReturn422OnPutWhenIdNotInRange() { 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_ENTITY) + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid Custom Label Name"); @@ -165,7 +165,7 @@ void shouldReturn422OnPutWhenInvalidNameLength() { 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_ENTITY) + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid request body"); diff --git a/src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java index 26a39c753..8bff0a0e7 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsExportImplIntegrationTest.java @@ -5,9 +5,9 @@ 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.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.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; @@ -22,7 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import io.restassured.http.Header; -import org.apache.http.HttpHeaders; +import org.folio.HttpHeaders; import org.folio.util.IntegrationTestBase; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; diff --git a/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java index ca092890e..6ebf82e34 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsKbCredentialsImplIntegrationTest.java @@ -1,10 +1,10 @@ package org.folio.rest.impl; -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_UNPROCESSABLE_ENTITY; +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; @@ -130,7 +130,7 @@ void shouldReturn422OnPostWhenCredentialsAreInvalid() { var postBody = Json.encode(kbCredentialsPostRequest); mockVerifyFailedCredentialsRequest(); - var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "KB API Credentials are invalid"); } @@ -143,7 +143,7 @@ void shouldReturn422OnPostWhenCredentialsNameIsLongerThen255() { var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); var postBody = Json.encode(kbCredentialsPostRequest); - var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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)"); @@ -157,7 +157,7 @@ void shouldReturn422OnPostWhenCredentialsNameIsEmpty() { var kbCredentialsPostRequest = new KbCredentialsPostRequest().withData(creds); var postBody = Json.encode(kbCredentialsPostRequest); - var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid name"); assertErrorContainsDetail(error, "name must not be empty"); @@ -170,7 +170,7 @@ void shouldReturn422OnPostWhenCredentialsWithProvidedNameAlreadyExist() { var postBody = Json.encode(kbCredentialsPostRequest); mockVerifyValidCredentialsRequest(); - var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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)); @@ -187,7 +187,7 @@ void shouldReturn422OnPostWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() var postBody = Json.encode(kbCredentialsPostRequest); mockVerifyValidCredentialsRequest(); - var error = postWithStatus(KB_CREDENTIALS_ENDPOINT, postBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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", @@ -271,7 +271,7 @@ void shouldReturn422OnPatchWhenCredentialsAreInvalid() { mockVerifyFailedCredentialsRequest(); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "KB API Credentials are invalid"); } @@ -284,7 +284,7 @@ void shouldReturn422OnPatchWhenCredentialsNameIsLongerThen255() { var patchBody = Json.encode(kbCredentialsPatchRequest); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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)"); @@ -299,7 +299,7 @@ void shouldReturn422OnPatchWhenCredentialsNameIsEmpty() { var patchBody = Json.encode(kbCredentialsPatchRequest); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid name"); assertErrorContainsDetail(error, "name must not be empty"); @@ -311,7 +311,7 @@ void shouldReturn422OnPatchWhenAllFieldsAreEmpty() { var patchBody = Json.encode(kbCredentialsPatchRequest); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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"); @@ -329,7 +329,7 @@ void shouldReturn422OnPatchWhenCredentialsWithProvidedNameAlreadyExist() { mockVerifyValidCredentialsRequest(); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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)); @@ -348,7 +348,7 @@ void shouldReturn422OnPatchWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() 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_ENTITY).as(JsonapiError.class); + 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", @@ -424,7 +424,7 @@ void shouldReturn422OnPutWhenCredentialsAreInvalid() { mockVerifyFailedCredentialsRequest(); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "KB API Credentials are invalid"); } @@ -438,7 +438,7 @@ void shouldReturn422OnPutWhenCredentialsNameIsLongerThen255() { var putBody = Json.encode(kbCredentialsPutRequest); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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)"); @@ -453,7 +453,7 @@ void shouldReturn422OnPutWhenCredentialsNameIsEmpty() { var putBody = Json.encode(kbCredentialsPutRequest); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/11111111-1111-1111-a111-111111111111"; - var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid name"); assertErrorContainsDetail(error, "name must not be empty"); @@ -469,7 +469,7 @@ void shouldReturn422OnPutWhenCredentialsWithProvidedNameAlreadyExist() { mockVerifyValidCredentialsRequest(); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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)); @@ -487,7 +487,7 @@ void shouldReturn422OnPutWhenCredentialsWithProvidedCustIdAndUrlAlreadyExist() { mockVerifyValidCredentialsRequest(); var resourcePath = KB_CREDENTIALS_ENDPOINT + "/" + credentialsId; - var error = putWithStatus(resourcePath, putBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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", diff --git a/src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java index f74ea5c9e..5afb43721 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsPackagesIntegrationTest.java @@ -10,14 +10,14 @@ 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.apache.http.HttpStatus.SC_BAD_REQUEST; -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_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.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; @@ -415,7 +415,7 @@ void shouldDoNothingOnPutWhenRequestHasNotTags() { 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_ENTITY) + var error = putWithStatus(tagsPath(FULL_PACKAGE_ID), Json.encode(tags), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid name"); @@ -639,7 +639,7 @@ void shouldDeleteAccessTypeMappingWhenRmApiSend404() { 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_ENTITY).as(JsonapiError.class); + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), 0); @@ -650,7 +650,7 @@ void shouldReturn422OnPutWhenUnselectNonCustomPackageIsHidden() { 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_ENTITY).as(JsonapiError.class); + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), putBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); verifyPut(WireMock.equalTo(packageRmApi(STUB_PACKAGE_ID)), 0); @@ -829,7 +829,7 @@ void shouldReturn400OnPutPackageWithNotExistedAccessType() { void shouldReturn422OnPutPackageWithInvalidAccessTypeId() { var requestBody = readFile(PUT_PACKAGE_WITH_INVALID_ACCESS_TYPE_REQUEST); - var error = putWithStatus(packagePath(FULL_PACKAGE_ID), requestBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); + var error = putWithStatus(packagePath(FULL_PACKAGE_ID), requestBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals(1, error.getErrors().size()); assertEquals( @@ -893,7 +893,7 @@ void shouldReturn400OnPostPackageWithNotExistedAccessType() { void shouldReturn422OnPostPackageWithInvalidAccessTypeId() { var requestBody = readFile(POST_PACKAGE_WITH_INVALID_ACCESS_TYPE_REQUEST); - var error = postWithStatus(packagesPath(), requestBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); + var error = postWithStatus(packagesPath(), requestBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals(1, error.getErrors().size()); assertEquals( @@ -1096,7 +1096,7 @@ void shouldFetchPackagesInBulk() { void shouldReturn422OnFetchPackagesInBulkWithInvalidIdFormat() { var postBody = readFile(POST_PACKAGES_BULK_WITH_INVALID_ID_REQUEST); - var error = postWithStatus(packagesBulkPath(), postBody, SC_UNPROCESSABLE_ENTITY).as(Errors.class); + var error = postWithStatus(packagesBulkPath(), postBody, SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals("elements in list must match pattern", error.getErrors().getFirst().getMessage()); } diff --git a/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java index 8a60da889..af3f22767 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsProvidersImplIntegrationTest.java @@ -4,11 +4,11 @@ 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.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.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; @@ -357,7 +357,7 @@ void shouldUpdateTagsOnPutTagsWithAlreadyExistingTags() { void shouldReturn422OnPutTagsWhenRequestBodyIsInvalid() { var tags = readJsonFile(PUT_PROVIDER_TAGS, PackageTagsPutRequest.class); tags.getData().getAttributes().setName(""); - var error = putWithStatus(providerTagsPath(), Json.encode(tags), SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = putWithStatus(providerTagsPath(), Json.encode(tags), SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid name"); assertErrorContainsDetail(error, "name must not be empty"); @@ -381,7 +381,7 @@ void shouldReturn422WhenBodyInputInvalidOnPut() { providerToBeUpdated.getData().getAttributes().setProviderToken(providerToken); var putBody = Json.encode(providerToBeUpdated); - var error = putWithStatus(PROVIDER_BY_ID, putBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + 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)"); diff --git a/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java index 0d0662e77..8b6f37c4b 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsProxyTypesImplIntegrationTest.java @@ -1,9 +1,9 @@ package org.folio.rest.impl; -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.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; diff --git a/src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java index b79c46f4d..9b48ea848 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsResourcesImplIntegrationTest.java @@ -4,11 +4,11 @@ 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.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.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; @@ -336,7 +336,7 @@ 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_ENTITY, CONTENT_TYPE_HEADER).as(Errors.class); + SC_UNPROCESSABLE_CONTENT, CONTENT_TYPE_HEADER).as(Errors.class); verifyPut(matching(managedResourceEndpoint), 0); @@ -412,7 +412,7 @@ 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_ENTITY).as(JsonapiError.class); + var error = putWithStatus(RESOURCE_TAGS_PATH, Json.encode(tags), SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid name"); } @@ -424,7 +424,7 @@ void shouldReturn422WhenInvalidUrlIsProvidedForCustomResource() { 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_ENTITY) + readFile(REQUEST_PUT_CUSTOM_RESOURCE_INVALID_URL), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid url"); @@ -466,7 +466,7 @@ void shouldReturn422IfPackageIsNotCustom() { mockTitle(RMAPI_GET_RESOURCE_BY_ID_SUCCESS); var error = - postWithStatus(RESOURCES_PATH, readFile(REQUEST_POST_RESOURCES), SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + postWithStatus(RESOURCES_PATH, readFile(REQUEST_POST_RESOURCES), SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertTrue(error.getErrors().getFirst().getTitle().contains("Invalid PackageId")); } @@ -534,7 +534,7 @@ void shouldReturnListWithBulkFetchResources() { @Test void shouldReturn422OnInvalidIdFormat() { var error = postWithStatus(RESOURCES_BULK_FETCH, readFile(REQUEST_POST_RESOURCES_BULK_INVALID_FORMAT), - SC_UNPROCESSABLE_ENTITY).as(Errors.class); + SC_UNPROCESSABLE_CONTENT).as(Errors.class); assertEquals("elements in list must match pattern", error.getErrors().getFirst().getMessage()); } diff --git a/src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java index 35433096c..8577996ea 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsRootProxyImplIntegrationTest.java @@ -2,12 +2,12 @@ import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.matching; -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.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; diff --git a/src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java index 8e08d4fdf..76b560f49 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsTagsImplIntegrationTest.java @@ -1,7 +1,7 @@ package org.folio.rest.impl; import static java.util.Arrays.asList; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; +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; @@ -104,8 +104,8 @@ void shouldReturnEmptyCollectionIfFilteredOutOnGet() { @Test void shouldFailOnInvalidRecordTypeOnGet() { - var error = getWithStatus(TAGS_PATH + "?filter[rectype]=INVALID&filter[rectype]=title", - SC_BAD_REQUEST).as(JsonapiError.class); + var error = getWithStatus(TAGS_PATH + "?filter[rectype]=INVALID&filter[rectype]=title", SC_BAD_REQUEST) + .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid 'filter[rectype]' parameter value"); } diff --git a/src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java index adcdab980..67303fe3a 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsTitlesIntegrationTest.java @@ -3,12 +3,12 @@ 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.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.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; @@ -495,7 +495,7 @@ void shouldUpdateTitleDataOnSecondPut() { @Test void shouldReturn422WhenNameIsNotProvided() { var error = putWithStatus(EHOLDINGS_TITLES_PATH + "/" + STUB_TITLE_ID, - readFile(PUT_TITLE_NULL_NAME_REQUEST), SC_UNPROCESSABLE_ENTITY) + readFile(PUT_TITLE_NULL_NAME_REQUEST), SC_UNPROCESSABLE_CONTENT) .as(Errors.class); assertTrue(error.getErrors().getFirst().getMessage().contains("must not be null")); diff --git a/src/test/java/org/folio/rest/impl/EholdingsUsageConsolidationImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/EholdingsUsageConsolidationImplIntegrationTest.java index 4993c3204..f3dff906f 100644 --- a/src/test/java/org/folio/rest/impl/EholdingsUsageConsolidationImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/EholdingsUsageConsolidationImplIntegrationTest.java @@ -2,10 +2,10 @@ import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.matching; -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_UNPROCESSABLE_ENTITY; +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; @@ -161,7 +161,7 @@ void shouldReturn422OnPatchWithInvalidCurrency() { .withCurrency(newCurrencyValue))); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - var error = patchWithStatus(resourcePath, Json.encode(patchData), SC_UNPROCESSABLE_ENTITY) + var error = patchWithStatus(resourcePath, Json.encode(patchData), SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid value"); @@ -200,7 +200,7 @@ void shouldReturn422OnPatchWithInvalidCustomerKey() { String patchBody = Json.encode(patchData); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); - var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_ENTITY) + var error = patchWithStatus(resourcePath, patchBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid UC Credentials"); @@ -247,7 +247,7 @@ void shouldReturn422OnPostSettingsWhenCurrencyIsInvalid() { var postRequest = getPostRequestNoDefault(); postRequest.getData().getAttributes().setCurrency("aaa"); String postBody = Json.encode(postRequest); - var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY) + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid value"); @@ -263,7 +263,7 @@ void shouldReturn422WhenKbCredentialsNotExist() { String randomCredentialsId = UUID.randomUUID().toString(); String resourcePath = String.format(UC_SETTINGS_ENDPOINT, randomCredentialsId); String postBody = Json.encode(getPostRequest()); - var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY) + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); String expectedErrorMessage = String.format("'%s' is invalid for 'kb_credentials_id'", randomCredentialsId); @@ -281,7 +281,7 @@ void shouldReturn422WhenSaveTwoEntitiesWithSameCredentialsId() { String postBody = Json.encode(getPostRequest()); postWithCreated(resourcePath, postBody); - var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY) + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); String expectedErrorMessage = String.format("'%s' is invalid for", credentialsId); @@ -295,7 +295,7 @@ void shouldReturn422WhenUcCredentialNotExist() { String resourcePath = String.format(UC_SETTINGS_ENDPOINT, credentialsId); String postBody = Json.encode(getPostRequest()); - var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_ENTITY) + var error = postWithStatus(resourcePath, postBody, SC_UNPROCESSABLE_CONTENT) .as(JsonapiError.class); String expectedErrorMessage = "Invalid UC API Credentials"; diff --git a/src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java b/src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java index b62a88332..2966665cd 100644 --- a/src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/TransactionLoadHoldingsImplIntegrationTest.java @@ -6,8 +6,8 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; -import static org.apache.http.HttpStatus.SC_NO_CONTENT; +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; diff --git a/src/test/java/org/folio/rest/impl/UsageConsolidationCredentialsApiIntegrationTest.java b/src/test/java/org/folio/rest/impl/UsageConsolidationCredentialsApiIntegrationTest.java index f83b1c072..7ef2f3f80 100644 --- a/src/test/java/org/folio/rest/impl/UsageConsolidationCredentialsApiIntegrationTest.java +++ b/src/test/java/org/folio/rest/impl/UsageConsolidationCredentialsApiIntegrationTest.java @@ -1,9 +1,9 @@ package org.folio.rest.impl; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; -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.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.TestUtil.clearDataFromTable; @@ -72,7 +72,7 @@ void shouldSaveNewInvalidUcCredentials() { mockAuthToken(SC_BAD_REQUEST); var requestBody = getRequestBody(STUB_CLIENT_ID, STUB_CLIENT_SECRET); - var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); var actualCredentials = getUcCredentials(vertx); @@ -104,7 +104,7 @@ void shouldNotUpdateExistingWithNewInvalidUcCredentials() { var newClientId = "NEW_ID"; var newClientSecret = "NEW_TOKEN"; var requestBody = getRequestBody(newClientId, newClientSecret); - var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_ENTITY).as(JsonapiError.class); + var error = putWithStatus(UC_CREDENTIALS_ENDPOINT, requestBody, SC_UNPROCESSABLE_CONTENT).as(JsonapiError.class); assertErrorContainsTitle(error, "Invalid Usage Consolidation Credentials"); var actualCredentials = getUcCredentials(vertx); diff --git a/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java b/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java index 555074713..ca59549cc 100644 --- a/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java +++ b/src/test/java/org/folio/service/uc/UcAuthServiceImplIntegrationTest.java @@ -1,7 +1,7 @@ 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.util.TestUtil.STUB_TENANT; import static org.folio.util.TestUtil.clearDataFromTable; diff --git a/src/test/java/org/folio/util/IntegrationTestBase.java b/src/test/java/org/folio/util/IntegrationTestBase.java index d44b81c9c..7b3009334 100644 --- a/src/test/java/org/folio/util/IntegrationTestBase.java +++ b/src/test/java/org/folio/util/IntegrationTestBase.java @@ -2,10 +2,10 @@ import static io.restassured.RestAssured.given; import static org.apache.hc.core5.http.ContentType.APPLICATION_JSON; -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.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; @@ -27,7 +27,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import org.apache.http.HttpHeaders; +import org.folio.HttpHeaders; import org.folio.cache.VertxCache; import org.folio.okapi.common.XOkapiHeaders; import org.folio.spring.SpringContextUtil; diff --git a/src/test/java/org/folio/util/WireMockTestBase.java b/src/test/java/org/folio/util/WireMockTestBase.java index 13c2bf1bc..f10e3c26b 100644 --- a/src/test/java/org/folio/util/WireMockTestBase.java +++ b/src/test/java/org/folio/util/WireMockTestBase.java @@ -13,10 +13,10 @@ 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.apache.http.HttpStatus.SC_FORBIDDEN; -import static org.apache.http.HttpStatus.SC_NOT_FOUND; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; +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; From e26a9e4a21923e4784c42a848d13daa80db717f4 Mon Sep 17 00:00:00 2001 From: Pavlo Smahin <pavlo_smahin@epam.com> Date: Fri, 26 Jun 2026 14:33:26 +0300 Subject: [PATCH 16/16] update news --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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))