Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MODPATRON-178 Allowed service points: switch to mod-circulation-bff #155

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ public static JsonObject verifyAndExtractBody(Response response) {
}
return new JsonObject(response.body);
}

public static JsonObject extractResponseBody(Response response) {
return isBlank(response.body) ? null : new JsonObject(response.body);
}
}
55 changes: 53 additions & 2 deletions src/main/java/org/folio/rest/impl/PatronServicesResourceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ public class PatronServicesResourceImpl implements Patron {
private static final String TOTAL_RECORDS = "totalRecords";
private static final String QUERY = "query";
private static final String CIRCULATION_REQUESTS = "/circulation/requests/%s";
private static final String CIRCULATION_REQUESTS_ALLOWED_SERVICE_POINTS =
private static final String CIRCULATION_REQUESTS_ALLOWED_SERVICE_POINTS_PATH =
"/circulation/requests/allowed-service-points";
private static final String CIRCULATION_BFF_ALLOWED_SERVICE_POINTS_PATH =
"/circulation-bff/allowed-service-points";
private static final String ACTIVE = "active";
private static final String PATRON_GROUP = "patronGroup";
private static final String ADDRESS_TYPES = "addressTypes";
Expand All @@ -121,6 +123,14 @@ public class PatronServicesResourceImpl implements Patron {
private static final String USERS_FILED = "users";
private static final String BAD_REQUEST_CODE = "BAD_REQUEST";
private static final String PROCESS_SINGLE_USER = "processSingleUser:: {}";
private static final String ECS_TLR_SETTINGS_PATH = "/tlr/settings";
private static final String ECS_TLR_FEATURE_KEY = "ecsTlrFeatureEnabled";
private static final String CIRCULATION_SETTINGS_KEY = "circulationSettings";
private static final int FIRST_POSITION_INDEX = 0;
private static final String VALUE_KEY = "value";
private static final String ENABLED_KEY = "enabled";
private static final String CIRCULATION_SETTINGS_STORAGE_PATH =
"/circulation-settings-storage/circulation-settings";

@Override
public void postPatronAccount(ExternalPatron entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
Expand Down Expand Up @@ -681,7 +691,7 @@ public void getPatronAccountInstanceAllowedServicePointsByIdAndInstanceId(String
var queryParameters = Map.of("operation", "create",
"requesterId", requesterId, "instanceId", instanceId);

completedFuture(CIRCULATION_REQUESTS_ALLOWED_SERVICE_POINTS)
getPathByEcsTlrFeatureEnabled(isEcsTlrFeatureEnabled(httpClient, okapiHeaders))
.thenCompose(path -> httpClient.get(path, queryParameters, okapiHeaders))
.thenApply(ResponseInterpreter::verifyAndExtractBody)
.thenApply(this::getAllowedServicePoints)
Expand Down Expand Up @@ -1167,4 +1177,45 @@ private String buildQueryWithRequesterId(String requesterId, String sortBy) {
return format("(requesterId==%s and status==Open*)", requesterId);
}

private CompletableFuture<Boolean> isEcsTlrFeatureEnabled(VertxOkapiHttpClient httpClient,
Map<String, String> okapiHeaders) {

return completedFuture(ECS_TLR_SETTINGS_PATH)
.thenCompose(path -> httpClient.get(path, Map.of(), okapiHeaders))
.thenApply(ResponseInterpreter::extractResponseBody)
.thenCompose(body -> getEcsTlrFeatureValue(body, httpClient, okapiHeaders));

}

private CompletableFuture<Boolean> getEcsTlrFeatureValue(JsonObject body,
VertxOkapiHttpClient client, Map<String, String> okapiHeaders) {

return Objects.nonNull(body)
? completedFuture(body.getBoolean(ECS_TLR_FEATURE_KEY))
: getCirculationStorageEcsTlrFeatureValue(client, okapiHeaders);
}

private CompletableFuture<Boolean> getCirculationStorageEcsTlrFeatureValue(
VertxOkapiHttpClient client, Map<String, String> okapiHeaders) {

return completedFuture(CIRCULATION_SETTINGS_STORAGE_PATH)
.thenCompose(path -> client.get(path, Map.of(), okapiHeaders))
.thenApply(ResponseInterpreter::extractResponseBody)
.thenCompose(this::getCirculationStorageEcsTlrFeatureValue);
}

private CompletableFuture<Boolean> getCirculationStorageEcsTlrFeatureValue(JsonObject body) {
return completedFuture(Objects.nonNull(body) && getEcsTlrFeatureValue(body));
}

private static Boolean getEcsTlrFeatureValue(JsonObject body) {
return body.getJsonArray(CIRCULATION_SETTINGS_KEY).getJsonObject(FIRST_POSITION_INDEX)
.getJsonObject(VALUE_KEY).getBoolean(ENABLED_KEY);
}

private CompletableFuture<String> getPathByEcsTlrFeatureEnabled(CompletableFuture<Boolean> result) {
return result.thenApply(value -> value
? CIRCULATION_BFF_ALLOWED_SERVICE_POINTS_PATH
: CIRCULATION_REQUESTS_ALLOWED_SERVICE_POINTS_PATH);
}
}
231 changes: 231 additions & 0 deletions src/test/java/org/folio/rest/impl/AllowedServicePointPathTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package org.folio.rest.impl;

import static io.restassured.RestAssured.given;
import static org.folio.patron.utils.Utils.readMockFile;
import static org.folio.rest.impl.PatronResourceImplTest.verifyAllowedServicePoints;

import java.util.stream.Stream;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.HttpStatus;
import org.folio.patron.utils.Utils;
import org.folio.rest.RestVerticle;
import org.folio.rest.tools.utils.ModuleName;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import io.restassured.RestAssured;
import io.restassured.http.Header;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.json.JsonObject;
import io.vertx.junit5.Checkpoint;
import io.vertx.junit5.VertxExtension;
import io.vertx.junit5.VertxTestContext;

@ExtendWith(VertxExtension.class)
public class AllowedServicePointPathTest {
public static final String CONTENT_TYPE_HEADER_NAME = "content-type";
private static final String CONTENT_TYPE_APPLICATION_JSON_HEADER = "application/json";
private static final String CIRCULATION_STORAGE_HEADER_NAME = "x-okapi-bad-user-id";
private static final String ECS_TLR_HEADER_NAME = "x-okapi-bad-data";
private static final String EMPTY_HEADER = "";
private static final String CIRCULATION_STORAGE_ENABLED_HEADER = "circulation-storage-true";
private static final String CIRCULATION_STORAGE_DISABLED_HEADER = "circulation-storage-false";
private static final String ECS_TLR_ENABLED_HEADER = "ecs-tlr-true";
private static final String ECS_TLR_DISABLED_HEADER = "ecs-tlr-false";
private static final String ECS_TLR_MOD_ENABLED_JSON_FILE_PATH =
"/ecs_tlr_module_feature_enabled.json";
private static final String ECS_TLR_MOD_DISABLED_JSON_FILE_PATH =
"/ecs_tlr_module_feature_disabled.json";
private static final String ECS_TLR_SETTINGS_PATH = "/tlr/settings";
private static final String CIRCULATION_STORAGE_MOD_ENABLED_JSON_FILE_PATH =
"/circulation_storage_module_feature_enabled.json";
private static final String CIRCULATION_STORAGE_MOD_DISABLED_JSON_FILE_PATH =
"/circulation_storage_module_feature_disabled.json";
public static final String ALLOWED_SERVICE_POINTS_CIRCULATION_JSON_FILE_PATH =
"/allowed_service_points_circulation.json";
public static final String ALLOWED_SERVICE_POINTS_CIRCULATION_BFF_JSON_FILE_PATH =
"/allowed_service_points_circulation_bff.json";
private static final String CIRCULATION_SETTINGS_STORAGE_PATH =
"/circulation-settings-storage/circulation-settings";
private static final String SERVICE_POINTS_CIRCULATION_BFF_RESPONSE_JSON =
"/allowed_service_points_circulation_bff_response.json";
private static final String CIRCULATION_REQUESTS_ALLOWED_SERVICE_POINTS_PATH =
"/circulation/requests/allowed-service-points";
private static final String CIRCULATION_BFF_ALLOWED_SERVICE_POINTS_PATH =
"/circulation-bff/allowed-service-points";
private static final String SERVICE_POINTS_CIRCULATION_RESPONSE_JSON =
"/allowed_service_points_circulation_response.json";
private static final String ACCOUNT_ID_PATH_PARAM_KEY = "accountId";
private static final String INSTANCE_ID_PATH_PARAM_KEY = "instanceId";
private final Logger logger = LogManager.getLogger();
private final int okapiPort = Utils.getRandomPort();
private final int serverPort = Utils.getRandomPort();

private final Header contentTypeHeader =
new Header("Content-Type", "application/json");
private final String mockDataFolder = "PatronServicesResourceImpl";
private final Header tenantHeader = new Header("X-Okapi-Tenant",
"patronresourceimpltest");
private final Header urlHeader = new Header("X-Okapi-Url", "http://localhost:" +
serverPort);
private final String goodUserId = "1ec54964-70f0-44cc-bd19-2a892ea0d336";
private final String goodInstanceId = "f39fd3ca-e3fb-4cd9-8cf9-48e7e2c494e5";
private final String accountPath = "/patron/account/{accountId}";
private final String instancePath = "/instance/{instanceId}";
private final String allowedServicePointsPath = "/allowed-service-points";

private String moduleName;
private String moduleVersion;
private String moduleId;

@BeforeEach
public void setUp(Vertx vertx, VertxTestContext context) {
vertx.exceptionHandler(context::failNow);

moduleName = ModuleName.getModuleName().replaceAll("_", "-");
moduleVersion = ModuleName.getModuleVersion();
moduleId = moduleName + "-" + moduleVersion;
logger.info("Test setup starting for {}", moduleId);

final JsonObject conf = new JsonObject();
conf.put("http.port", okapiPort);

final Checkpoint verticleStarted = context.checkpoint(1);
final Checkpoint mockOkapiStarted = context.checkpoint(1);

final DeploymentOptions opt = new DeploymentOptions().setConfig(conf);
vertx.deployVerticle(RestVerticle.class.getName(), opt,
context.succeeding(id -> verticleStarted.flag()));
RestAssured.port = okapiPort;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
logger.info("Patron Services Test Setup Done using port {}", okapiPort);

final String host = "localhost";

final HttpServer server = vertx.createHttpServer();
server.requestHandler(req -> {
if (req.path().equals(CIRCULATION_REQUESTS_ALLOWED_SERVICE_POINTS_PATH)) {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(mockDataFolder +
ALLOWED_SERVICE_POINTS_CIRCULATION_JSON_FILE_PATH));
} else if (req.path().equals(CIRCULATION_BFF_ALLOWED_SERVICE_POINTS_PATH)) {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(mockDataFolder +
ALLOWED_SERVICE_POINTS_CIRCULATION_BFF_JSON_FILE_PATH));
} else if (req.path().equals(ECS_TLR_SETTINGS_PATH)) {
if (req.getHeader(ECS_TLR_HEADER_NAME).isEmpty()) {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(null));
} else if (req.getHeader(ECS_TLR_HEADER_NAME).equals(ECS_TLR_ENABLED_HEADER)) {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(mockDataFolder + ECS_TLR_MOD_ENABLED_JSON_FILE_PATH));
} else {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(mockDataFolder + ECS_TLR_MOD_DISABLED_JSON_FILE_PATH));
}
} else if (req.path().equals(CIRCULATION_SETTINGS_STORAGE_PATH)) {
if (req.getHeader(CIRCULATION_STORAGE_HEADER_NAME)
.equals(CIRCULATION_STORAGE_ENABLED_HEADER)) {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(mockDataFolder +
CIRCULATION_STORAGE_MOD_ENABLED_JSON_FILE_PATH));
} else if (req.getHeader(CIRCULATION_STORAGE_HEADER_NAME).isEmpty()) {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(null));
} else {
req.response()
.setStatusCode(HttpStatus.HTTP_OK.toInt())
.putHeader(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_APPLICATION_JSON_HEADER)
.end(readMockFile(mockDataFolder +
CIRCULATION_STORAGE_MOD_DISABLED_JSON_FILE_PATH));
}
}
});
server.listen(serverPort, host, context.succeeding(id -> mockOkapiStarted.flag()));
}

@AfterEach
public void tearDown(Vertx vertx, VertxTestContext context) {
logger.info("Patron Services Testing Complete");
vertx.close(ar -> {
if (ar.succeeded()) {
context.completeNow();
} else {
context.failNow(ar.cause());
}
});
}

@ParameterizedTest
@MethodSource("headerValueToFileName")
void getAllowedServicePointsShouldUseCorrectRoutingPathTest(String tlrHeaderValue,
String circulationStoragesHeaderValue, String expectedServicePointsResponseFileName) {

var response = given()
.header(new Header(ECS_TLR_HEADER_NAME, tlrHeaderValue))
.header(new Header(CIRCULATION_STORAGE_HEADER_NAME, circulationStoragesHeaderValue))
.header(tenantHeader)
.header(urlHeader)
.header(contentTypeHeader)
.pathParam(ACCOUNT_ID_PATH_PARAM_KEY, goodUserId)
.pathParam(INSTANCE_ID_PATH_PARAM_KEY, goodInstanceId)
.log().all()
.when()
.get(accountPath + instancePath + allowedServicePointsPath)
.then()
.extract()
.asString();

final JsonObject expectedJson = new JsonObject(readMockFile(mockDataFolder +
expectedServicePointsResponseFileName));

verifyAllowedServicePoints(expectedJson, new JsonObject(response));
}

private static Stream<Arguments> headerValueToFileName() {
return Stream.of(
Arguments.of(
ECS_TLR_ENABLED_HEADER, EMPTY_HEADER,
SERVICE_POINTS_CIRCULATION_BFF_RESPONSE_JSON
),
Arguments.of(
ECS_TLR_DISABLED_HEADER, EMPTY_HEADER,
SERVICE_POINTS_CIRCULATION_RESPONSE_JSON
),
Arguments.of(
EMPTY_HEADER, CIRCULATION_STORAGE_ENABLED_HEADER,
SERVICE_POINTS_CIRCULATION_BFF_RESPONSE_JSON
),
Arguments.of(
EMPTY_HEADER, CIRCULATION_STORAGE_DISABLED_HEADER,
SERVICE_POINTS_CIRCULATION_RESPONSE_JSON
),
Arguments.of(
EMPTY_HEADER, EMPTY_HEADER, SERVICE_POINTS_CIRCULATION_RESPONSE_JSON
)
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2215,7 +2215,7 @@ private boolean verifyItem(JsonObject expectedItem, JsonObject actualItem) {
return false;
}

private void verifyAllowedServicePoints(JsonObject expectedAllowedServicePoints,
public static void verifyAllowedServicePoints(JsonObject expectedAllowedServicePoints,
JsonObject actualAllowedServicePoints) {

JsonArray expectedAllowedServicePointsArray = expectedAllowedServicePoints
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"Hold" : [ {
"id" : "3a40852d-49fd-4df2-a1f9-6e2641a61111",
"name" : "Circ Desk 1"
}, {
"id" : "c4c90014-c8c9-4ade-8f24-b5e313312222",
"name" : "Circ Desk 2"
} ],
"Recall" : [ {
"id" : "7c5abc9f-f3d7-4856-b8d7-6712462c3333",
"name" : "Online"
} ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Hold" : [ {
"id" : "3a40852d-49fd-4df2-a1f9-6e2641a66666",
"name" : "Circ Desk 1"
} ],
"Recall" : [ {
"id" : "7c5abc9f-f3d7-4856-b8d7-6712462c7777",
"name" : "Online"
} ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"allowedServicePoints" : [ {
"id" : "3a40852d-49fd-4df2-a1f9-6e2641a66666",
"name" : "Circ Desk 1"
}, {
"id" : "7c5abc9f-f3d7-4856-b8d7-6712462c7777",
"name" : "Online"
} ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"allowedServicePoints" : [ {
"id" : "3a40852d-49fd-4df2-a1f9-6e2641a61111",
"name" : "Circ Desk 1"
}, {
"id" : "c4c90014-c8c9-4ade-8f24-b5e313312222",
"name" : "Circ Desk 2"
}, {
"id" : "7c5abc9f-f3d7-4856-b8d7-6712462c3333",
"name" : "Online"
} ]
}
Loading