diff --git a/ramls/request-queue-reordering.json b/ramls/request-queue-reordering.json new file mode 100644 index 000000000..8098f1dda --- /dev/null +++ b/ramls/request-queue-reordering.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Requests batch update", + "description": "List of ids reordered requests", + "type": "object", + "properties": { + "instanceId": { + "description": "Instance ID of reordered requests", + "type": "string", + "$ref": "raml-util/schemas/uuid.schema" + }, + "itemId": { + "description": "Item ID of reordered requests", + "type": "string", + "$ref": "raml-util/schemas/uuid.schema" + }, + "requestLevel": { + "description": "Level of the request - Item or Title", + "type": "string", + "enum": ["Item", "Title"] + }, + "requestIds": { + "description": "Array of requests ids", + "type": "array", + "items": { + "type": "string", + "$ref": "raml-util/schemas/uuid.schema" + } + } + }, + "additionalProperties": false, + "required": [ + "requestLevel" + ] +} diff --git a/ramls/request-storage-batch.raml b/ramls/request-storage-batch.raml index 372865083..a6f0aaaae 100644 --- a/ramls/request-storage-batch.raml +++ b/ramls/request-storage-batch.raml @@ -11,6 +11,7 @@ documentation: types: requests-batch: !include requests-batch.json errors: !include raml-util/schemas/errors.schema + request-queue-reordering: !include request-queue-reordering.json traits: validate: !include raml-util/traits/validation.raml diff --git a/ramls/request.json b/ramls/request.json index 65d64544b..8c1f54231 100644 --- a/ramls/request.json +++ b/ramls/request.json @@ -18,6 +18,11 @@ "type": "string", "enum": ["Hold", "Recall", "Page"] }, + "ecsRequestPhase": { + "description": "Stage in ECS request process, absence of this field means this is a single-tenant request", + "type": "string", + "enum": ["Primary", "Secondary"] + }, "requestDate": { "description": "Date the request was made", "type": "string", diff --git a/src/main/java/org/folio/rest/impl/CirculationSettingsAPI.java b/src/main/java/org/folio/rest/impl/CirculationSettingsAPI.java index 86dda0e09..fbf1758fc 100644 --- a/src/main/java/org/folio/rest/impl/CirculationSettingsAPI.java +++ b/src/main/java/org/folio/rest/impl/CirculationSettingsAPI.java @@ -47,9 +47,9 @@ public void getCirculationSettingsStorageCirculationSettingsByCirculationSetting String circulationSettingsId, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - new CirculationSettingsService(vertxContext, okapiHeaders) - .findById(circulationSettingsId) - .onComplete(asyncResultHandler); + new CirculationSettingsService(vertxContext, okapiHeaders) + .findById(circulationSettingsId) + .onComplete(asyncResultHandler); } @Override @@ -57,9 +57,9 @@ public void putCirculationSettingsStorageCirculationSettingsByCirculationSetting String circulationSettingsId, CirculationSetting entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - new CirculationSettingsService(vertxContext, okapiHeaders) - .update(circulationSettingsId, entity) - .onComplete(asyncResultHandler); + new CirculationSettingsService(vertxContext, okapiHeaders) + .update(circulationSettingsId, entity) + .onComplete(asyncResultHandler); } @Override @@ -67,8 +67,8 @@ public void deleteCirculationSettingsStorageCirculationSettingsByCirculationSett String circulationSettingsId, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - new CirculationSettingsService(vertxContext, okapiHeaders) - .delete(circulationSettingsId) - .onComplete(asyncResultHandler); + new CirculationSettingsService(vertxContext, okapiHeaders) + .delete(circulationSettingsId) + .onComplete(asyncResultHandler); } } diff --git a/src/main/java/org/folio/rest/impl/RequestsBatchAPI.java b/src/main/java/org/folio/rest/impl/RequestsBatchAPI.java index ca7848ea5..d83da9321 100644 --- a/src/main/java/org/folio/rest/impl/RequestsBatchAPI.java +++ b/src/main/java/org/folio/rest/impl/RequestsBatchAPI.java @@ -6,7 +6,6 @@ import static org.folio.rest.jaxrs.resource.RequestStorageBatch.PostRequestStorageBatchRequestsResponse.respond201; import static org.folio.rest.jaxrs.resource.RequestStorageBatch.PostRequestStorageBatchRequestsResponse.respond422WithApplicationJson; import static org.folio.rest.jaxrs.resource.RequestStorageBatch.PostRequestStorageBatchRequestsResponse.respond500WithTextPlain; -import static org.folio.rest.tools.utils.TenantTool.tenantId; import java.util.Map; @@ -14,9 +13,7 @@ import org.folio.rest.annotations.Validate; import org.folio.rest.jaxrs.model.RequestsBatch; import org.folio.rest.jaxrs.resource.RequestStorageBatch; -import org.folio.rest.persist.PgUtil; import org.folio.rest.tools.utils.MetadataUtil; -import org.folio.service.BatchResourceService; import org.folio.service.request.RequestBatchResourceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,7 +23,7 @@ import io.vertx.core.Handler; public class RequestsBatchAPI implements RequestStorageBatch { - private static final Logger LOG = LoggerFactory.getLogger(RequestsBatchAPI.class); + private static final Logger log = LoggerFactory.getLogger(RequestsBatchAPI.class); @Validate @Override @@ -38,36 +35,30 @@ public void postRequestStorageBatchRequests( MetadataUtil.populateMetadata(entity.getRequests(), okapiHeaders); } catch (Throwable e) { String msg = "Cannot populate metadata of request list elements: " + e.getMessage(); - LOG.error(msg, e); + log.error(msg, e); asyncResultHandler.handle(succeededFuture(respond500WithTextPlain(msg))); return; } - BatchResourceService batchUpdateService = new BatchResourceService( - PgUtil.postgresClient(context, okapiHeaders) - ); - - RequestBatchResourceService requestBatchUpdateService = - new RequestBatchResourceService(tenantId(okapiHeaders), batchUpdateService); - - requestBatchUpdateService.executeRequestBatchUpdate(entity.getRequests(), - updateResult -> { + log.info("postRequestStorageBatchRequests:: requests: {}", entity.getRequests()); + new RequestBatchResourceService(context, okapiHeaders) + .executeRequestBatchUpdate(entity.getRequests(), updateResult -> { // Successfully updated if (updateResult.succeeded()) { - LOG.debug("Batch update executed successfully"); + log.debug("Batch update executed successfully"); asyncResultHandler.handle(succeededFuture(respond201())); return; } // Update failed due to can not have more then one request in the same position if (hasSamePositionConstraintViolated(updateResult.cause())) { - LOG.warn("Same position constraint violated", updateResult.cause()); + log.warn("Same position constraint violated", updateResult.cause()); asyncResultHandler.handle(succeededFuture( respond422WithApplicationJson(samePositionInQueueError(null, null)) )); } else { // Other failure occurred - LOG.warn("Unhandled error occurred during update", updateResult.cause()); + log.warn("Unhandled error occurred during update", updateResult.cause()); asyncResultHandler.handle(succeededFuture( respond500WithTextPlain(updateResult.cause().getMessage()) )); diff --git a/src/main/java/org/folio/service/BatchResourceService.java b/src/main/java/org/folio/service/BatchResourceService.java index f1ef94069..53f6e90b6 100644 --- a/src/main/java/org/folio/service/BatchResourceService.java +++ b/src/main/java/org/folio/service/BatchResourceService.java @@ -23,7 +23,7 @@ import io.vertx.sqlclient.RowSet; public class BatchResourceService { - private static final Logger LOG = LoggerFactory.getLogger(BatchResourceService.class); + private static final Logger log = LoggerFactory.getLogger(BatchResourceService.class); private static final String WHERE_CLAUSE = "WHERE id = '%s'"; private final PostgresClient postgresClient; @@ -38,14 +38,17 @@ public BatchResourceService(PostgresClient postgresClient) { * @param batchFactories - Factory to create a batch update chunk. * @param onFinishHandler - Callback. */ - public void executeBatchUpdate( + public Future executeBatchUpdate( List>>> batchFactories, Handler> onFinishHandler) { + Promise promise = Promise.promise(); + postgresClient.startTx(connectionResult -> { if (connectionResult.failed()) { - LOG.warn("Can not start transaction", connectionResult.cause()); + log.warn("Cannot start transaction", connectionResult.cause()); onFinishHandler.handle(failedFuture(connectionResult.cause())); + promise.fail(connectionResult.cause()); return; } @@ -60,21 +63,32 @@ public void executeBatchUpdate( // Handle overall update result and decide on whether to commit or rollback transaction lastUpdate.onComplete(updateResult -> { if (updateResult.failed()) { - LOG.warn("Batch update rejected", updateResult.cause()); + log.warn("Batch update rejected", updateResult.cause()); // Rollback transaction and keep original cause. - postgresClient.rollbackTx(connectionResult, - rollback -> onFinishHandler.handle(failedFuture(updateResult.cause())) - ); + postgresClient.rollbackTx(connectionResult, rollback -> { + onFinishHandler.handle(failedFuture(updateResult.cause())); + promise.fail(updateResult.cause()); + }); } else { - LOG.debug("Update successful, committing transaction"); - - postgresClient.endTx(connectionResult, onFinishHandler); + log.debug("Update successful, committing transaction"); + + postgresClient.endTx(connectionResult, commitResult -> { + if (commitResult.succeeded()) { + onFinishHandler.handle(succeededFuture()); + promise.complete(); + } else { + log.warn("Failed to commit transaction", commitResult.cause()); + onFinishHandler.handle(failedFuture(commitResult.cause())); + promise.fail(commitResult.cause()); + } + }); } }); }); - } + return promise.future(); + } /** * Creates update single entity batch function. * @@ -92,7 +106,7 @@ public Function>> updateSingleEntityBatchF final Promise> promise = promise(); final Future connectionResult = succeededFuture(connection); - LOG.debug("Updating entity {} with id {}", entity, id); + log.debug("Updating entity {} with id {}", entity, id); postgresClient.update(connectionResult, tableName, entity, "jsonb", String.format(WHERE_CLAUSE, id), false, promise); @@ -113,7 +127,7 @@ public Function>> queryWithParamsBatchFactory( String query, Collection params) { return connection -> { - LOG.debug("Executing SQL [{}], got [{}] parameters", query, params.size()); + log.debug("Executing SQL [{}], got [{}] parameters", query, params.size()); final Promise> promise = promise(); final Future connectionResult = succeededFuture(connection); diff --git a/src/main/java/org/folio/service/CirculationSettingsService.java b/src/main/java/org/folio/service/CirculationSettingsService.java index c68285fa4..b08f61319 100644 --- a/src/main/java/org/folio/service/CirculationSettingsService.java +++ b/src/main/java/org/folio/service/CirculationSettingsService.java @@ -60,17 +60,21 @@ public Future findById(String circulationSettingsId) { GetCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class); } - public Future update(String circulationSettingsId, CirculationSetting circulationSetting) { - return PgUtil.put(CIRCULATION_SETTINGS_TABLE, circulationSetting, circulationSettingsId, okapiHeaders, vertxContext, + public Future update(String circulationSettingsId, + CirculationSetting circulationSetting) { + + return PgUtil.put(CIRCULATION_SETTINGS_TABLE, circulationSetting, circulationSettingsId, + okapiHeaders, vertxContext, PutCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class) .compose(eventPublisher.publishUpdated(circulationSetting)); } public Future delete(String circulationSettingsId) { - return repository.getById(circulationSettingsId).compose ( - circulationSetting -> PgUtil.deleteById(CIRCULATION_SETTINGS_TABLE, circulationSettingsId, okapiHeaders, vertxContext, - DeleteCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class) - .compose(eventPublisher.publishRemoved(circulationSetting)) + return repository.getById(circulationSettingsId) + .compose(circulationSetting -> PgUtil.deleteById(CIRCULATION_SETTINGS_TABLE, + circulationSettingsId, okapiHeaders, vertxContext, + DeleteCirculationSettingsStorageCirculationSettingsByCirculationSettingsIdResponse.class) + .compose(eventPublisher.publishRemoved(circulationSetting)) ); } @@ -109,4 +113,4 @@ private Future> getSettingsByName(String settingsName) return repository.get(filter); } -} \ No newline at end of file +} diff --git a/src/main/java/org/folio/service/event/EntityChangedEventPublisherFactory.java b/src/main/java/org/folio/service/event/EntityChangedEventPublisherFactory.java index 54eccfe90..7f37dc8b1 100644 --- a/src/main/java/org/folio/service/event/EntityChangedEventPublisherFactory.java +++ b/src/main/java/org/folio/service/event/EntityChangedEventPublisherFactory.java @@ -5,6 +5,7 @@ import static org.folio.support.kafka.topic.CirculationStorageKafkaTopic.CIRCULATION_SETTINGS; import static org.folio.support.kafka.topic.CirculationStorageKafkaTopic.LOAN; import static org.folio.support.kafka.topic.CirculationStorageKafkaTopic.REQUEST; +import static org.folio.support.kafka.topic.CirculationStorageKafkaTopic.REQUEST_QUEUE_REORDERING; import static org.folio.support.kafka.topic.CirculationStorageKafkaTopic.RULES; import java.util.Map; @@ -19,6 +20,7 @@ import org.folio.rest.jaxrs.model.CirculationSetting; import org.folio.rest.jaxrs.model.Loan; import org.folio.rest.jaxrs.model.Request; +import org.folio.rest.jaxrs.model.RequestQueueReordering; import io.vertx.core.Context; import lombok.extern.log4j.Log4j2; @@ -53,6 +55,15 @@ public static EntityChangedEventPublisher requestEventPublisher new RequestRepository(vertxContext, okapiHeaders)); } + public static EntityChangedEventPublisher + requestBatchEventPublisher(Context vertxContext, Map okapiHeaders) { + + return new EntityChangedEventPublisher<>(okapiHeaders, RequestQueueReordering::getInstanceId, + NULL_ID, new EntityChangedEventFactory<>(), new DomainEventPublisher<>(vertxContext, + REQUEST_QUEUE_REORDERING.fullTopicName(tenantId(okapiHeaders)), + FailureHandler.noOperation()), null); + } + public static EntityChangedEventPublisher checkInEventPublisher( Context vertxContext, Map okapiHeaders) { diff --git a/src/main/java/org/folio/service/request/RequestBatchResourceService.java b/src/main/java/org/folio/service/request/RequestBatchResourceService.java index 87a7ba44b..c863b1937 100644 --- a/src/main/java/org/folio/service/request/RequestBatchResourceService.java +++ b/src/main/java/org/folio/service/request/RequestBatchResourceService.java @@ -2,39 +2,47 @@ import static java.util.stream.IntStream.rangeClosed; import static org.folio.rest.persist.PostgresClient.convertToPsqlStandard; +import static org.folio.rest.tools.utils.TenantTool.tenantId; +import static org.folio.service.event.EntityChangedEventPublisherFactory.requestBatchEventPublisher; import static org.folio.support.ModuleConstants.REQUEST_TABLE; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import org.folio.rest.jaxrs.model.Request; +import org.folio.rest.jaxrs.model.RequestQueueReordering; +import org.folio.rest.persist.PgUtil; import org.folio.rest.persist.SQLConnection; import org.folio.service.BatchResourceService; +import org.folio.service.event.EntityChangedEventPublisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.vertx.core.AsyncResult; +import io.vertx.core.Context; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; public class RequestBatchResourceService { - private static final Logger LOG = LoggerFactory.getLogger(RequestBatchResourceService.class); + private static final Logger log = LoggerFactory.getLogger(RequestBatchResourceService.class); private static final String REMOVE_POSITIONS_SQL = "UPDATE %s.%s SET jsonb = jsonb - 'position' WHERE id::text IN (%s)"; private final BatchResourceService batchResourceService; private final String tenantName; + private final EntityChangedEventPublisher eventPublisher; - public RequestBatchResourceService(String tenantName, - BatchResourceService batchResourceService) { - - this.batchResourceService = batchResourceService; - this.tenantName = tenantName; + public RequestBatchResourceService(Context context, Map okapiHeaders) { + this.batchResourceService = new BatchResourceService(PgUtil.postgresClient(context, + okapiHeaders)); + this.tenantName = tenantId(okapiHeaders); + this.eventPublisher = requestBatchEventPublisher(context, okapiHeaders); } /** @@ -59,10 +67,10 @@ public RequestBatchResourceService(String tenantName, * @param requests - List of requests to execute in batch. * @param onFinishHandler - Callback function. */ - public void executeRequestBatchUpdate( - List requests, Handler> onFinishHandler) { + public void executeRequestBatchUpdate(List requests, + Handler> onFinishHandler) { - LOG.debug("Removing positions for all request to go through positions constraint"); + log.debug("Removing positions for all request to go through positions constraint"); List>>> allDatabaseOperations = new ArrayList<>(); @@ -77,10 +85,29 @@ public void executeRequestBatchUpdate( allDatabaseOperations.add(removePositionBatch); allDatabaseOperations.addAll(updateRequestsBatch); - LOG.info("Executing batch update, total records to update [{}] (including remove positions)", + log.info("Executing batch update, total records to update [{}] (including remove positions)", allDatabaseOperations.size()); - batchResourceService.executeBatchUpdate(allDatabaseOperations, onFinishHandler); + RequestQueueReordering payload = mapRequestsToPayload(requests); + log.info("executeRequestBatchUpdate:: instanceId: {}, itemId: {}, requestLevel: {}, " + + "requests: {}", payload.getInstanceId(), payload.getItemId(), payload.getRequestLevel(), + payload.getRequestIds()); + + batchResourceService.executeBatchUpdate(allDatabaseOperations, onFinishHandler) + .compose(v -> eventPublisher.publishCreated(payload.getInstanceId(), payload)); + } + + private RequestQueueReordering mapRequestsToPayload(List requests) { + var firstRequest = requests.get(0); + + return new RequestQueueReordering() + .withRequestIds(requests.stream() + .map(Request::getId) + .toList()) + .withInstanceId(firstRequest.getInstanceId()) + .withItemId(firstRequest.getItemId()) + .withRequestLevel(RequestQueueReordering.RequestLevel.valueOf( + firstRequest.getRequestLevel().name())); } private Function>> removePositionsForRequestsBatch( diff --git a/src/main/java/org/folio/support/kafka/topic/CirculationStorageKafkaTopic.java b/src/main/java/org/folio/support/kafka/topic/CirculationStorageKafkaTopic.java index 0f4ec85b3..4dc536f1b 100644 --- a/src/main/java/org/folio/support/kafka/topic/CirculationStorageKafkaTopic.java +++ b/src/main/java/org/folio/support/kafka/topic/CirculationStorageKafkaTopic.java @@ -4,6 +4,7 @@ public enum CirculationStorageKafkaTopic implements KafkaTopic { REQUEST("request", 10), + REQUEST_QUEUE_REORDERING("request-queue-reordering", 10), CIRCULATION_SETTINGS("circulation-settings", 10), LOAN("loan", 10), CHECK_IN("check-in", 10), diff --git a/src/main/resources/templates/db_scripts/add_staff_slips_transit_mediated_requests.sql b/src/main/resources/templates/db_scripts/add_staff_slips_transit_mediated_requests.sql new file mode 100644 index 000000000..2dfd420ae --- /dev/null +++ b/src/main/resources/templates/db_scripts/add_staff_slips_transit_mediated_requests.sql @@ -0,0 +1,8 @@ +INSERT INTO ${myuniversity}_${mymodule}.staff_slips(id, jsonb) +VALUES ('e6e29ec1-1a76-4913-bbd3-65f4ffd94e04', + jsonb_build_object( + 'id', 'e6e29ec1-1a76-4913-bbd3-65f4ffd94e04', + 'name', 'Transit (mediated requests)', + 'active', true, + 'template', '

')) +ON CONFLICT DO NOTHING; \ No newline at end of file diff --git a/src/main/resources/templates/db_scripts/schema.json b/src/main/resources/templates/db_scripts/schema.json index b0390bd67..bc1b06ae2 100644 --- a/src/main/resources/templates/db_scripts/schema.json +++ b/src/main/resources/templates/db_scripts/schema.json @@ -574,6 +574,11 @@ "snippetPath": "add_search_slips.sql", "fromModuleVersion": "17.2.0" }, + { + "run": "after", + "snippetPath": "add_staff_slips_transit_mediated_requests.sql", + "fromModuleVersion": "17.3.0" + }, { "run": "after", "snippetPath": "removePositionFromClosedRequests.sql", diff --git a/src/test/java/org/folio/rest/api/CirculationSettingsAPITest.java b/src/test/java/org/folio/rest/api/CirculationSettingsAPITest.java index 08c928613..fec71d3f2 100644 --- a/src/test/java/org/folio/rest/api/CirculationSettingsAPITest.java +++ b/src/test/java/org/folio/rest/api/CirculationSettingsAPITest.java @@ -144,4 +144,4 @@ private JsonObject getUpdatedSettingsJson() { circulationSettingsJsonUpdated.put(VALUE_KEY, updatedValue); return circulationSettingsJsonUpdated; } -} \ No newline at end of file +} diff --git a/src/test/java/org/folio/rest/api/RequestBatchAPITest.java b/src/test/java/org/folio/rest/api/RequestBatchAPITest.java index 51ee63662..234733aab 100644 --- a/src/test/java/org/folio/rest/api/RequestBatchAPITest.java +++ b/src/test/java/org/folio/rest/api/RequestBatchAPITest.java @@ -3,21 +3,27 @@ import static org.folio.rest.api.RequestsApiTest.requestStorageUrl; import static org.folio.rest.api.StorageTestSuite.TENANT_ID; import static org.folio.rest.api.StorageTestSuite.storageUrl; +import static org.folio.rest.jaxrs.model.RequestQueueReordering.RequestLevel.TITLE; +import static org.folio.rest.support.kafka.FakeKafkaConsumer.removeAllEvents; +import static org.folio.rest.support.matchers.DomainEventAssertions.assertRequestQueueReorderingEvent; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import java.net.URL; import java.util.Arrays; import java.util.Comparator; +import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Function; + import org.folio.rest.impl.RequestsBatchAPI; import org.folio.rest.jaxrs.model.Request; +import org.folio.rest.jaxrs.model.RequestQueueReordering; import org.folio.rest.support.ApiTests; import org.folio.rest.support.JsonResponse; import org.folio.rest.support.Response; @@ -41,6 +47,7 @@ public class RequestBatchAPITest extends ApiTests { @Before public void beforeEach() throws Exception { StorageTestSuite.deleteAll(requestStorageUrl()); + removeAllEvents(); } @After @@ -52,8 +59,8 @@ public void checkIdsAfterEach() { public void canUpdateRequestPositionsInBatch() throws Exception { UUID itemId = UUID.randomUUID(); - JsonObject firstRequest = createRequestForItemAtPosition(itemId, 1); - JsonObject secondRequest = createRequestForItemAtPosition(itemId, 2); + JsonObject firstRequest = createRequestAtPosition(itemId, null, 1); + JsonObject secondRequest = createRequestAtPosition(itemId, null, 2); ReorderRequest firstReorderRequest = new ReorderRequest(firstRequest, 2); ReorderRequest secondReorderRequest = new ReorderRequest(secondRequest, 1); @@ -81,8 +88,8 @@ public void canUpdateRequestPositionsInBatch() throws Exception { public void canCloseRequestsInBatch() throws Exception { UUID itemId = UUID.randomUUID(); - JsonObject firstRequest = createRequestForItemAtPosition(itemId, 1); - JsonObject secondRequest = createRequestForItemAtPosition(itemId, 2); + JsonObject firstRequest = createRequestAtPosition(itemId, null, 1); + JsonObject secondRequest = createRequestAtPosition(itemId, null, 2); firstRequest.put("status", Request.Status.CLOSED_FILLED.value()); firstRequest.remove("position"); @@ -111,8 +118,8 @@ public void canCloseRequestsInBatch() throws Exception { public void canUpdateRequestFulfillmentPreferenceInBatch() throws Exception { UUID itemId = UUID.randomUUID(); - JsonObject firstRequest = createRequestForItemAtPosition(itemId, 1); - JsonObject secondRequest = createRequestForItemAtPosition(itemId, 2); + JsonObject firstRequest = createRequestAtPosition(itemId, null, 1); + JsonObject secondRequest = createRequestAtPosition(itemId, null, 2); firstRequest.put("fulfillmentPreference", "Delivery"); secondRequest.put("fulfillmentPreference", "Delivery"); @@ -153,8 +160,8 @@ public void willAbortBatchUpdateOnPopulateMetadataException() throws Exception { public void willAbortBatchUpdateForRequestsAtTheSamePositionInAnItemsQueue() throws Exception { UUID itemId = UUID.randomUUID(); - JsonObject firstRequest = createRequestForItemAtPosition(itemId, 1); - JsonObject secondRequest = createRequestForItemAtPosition(itemId, 2); + JsonObject firstRequest = createRequestAtPosition(itemId, null, 1); + JsonObject secondRequest = createRequestAtPosition(itemId, null, 2); JsonResponse reorderResponse = attemptReorderRequests(ResponseHandler::json, new ReorderRequest(firstRequest, 1), @@ -170,8 +177,8 @@ public void willAbortBatchUpdateForRequestsAtTheSamePositionInAnItemsQueue() thr public void willAbortBatchUpdateWhenOnlyOnePositionIsModified() throws Exception { UUID itemId = UUID.randomUUID(); - JsonObject firstRequest = createRequestForItemAtPosition(itemId, 1); - JsonObject secondRequest = createRequestForItemAtPosition(itemId, 2); + JsonObject firstRequest = createRequestAtPosition(itemId, null, 1); + JsonObject secondRequest = createRequestAtPosition(itemId, null, 2); JsonResponse reorderResponse = attemptReorderRequests(ResponseHandler::json, new ReorderRequest(firstRequest, 2) @@ -186,8 +193,8 @@ public void willAbortBatchUpdateWhenOnlyOnePositionIsModified() throws Exception public void willAbortBatchUpdateOnNullPointerExceptionDueToNoIdInRequest() throws Exception { UUID itemId = UUID.randomUUID(); - JsonObject firstRequest = createRequestForItemAtPosition(itemId, 1); - JsonObject secondRequest = createRequestForItemAtPosition(itemId, 2); + JsonObject firstRequest = createRequestAtPosition(itemId, null, 1); + JsonObject secondRequest = createRequestAtPosition(itemId, null, 2); JsonObject firstRequestCopy = firstRequest.copy(); firstRequestCopy.remove("id"); @@ -205,7 +212,7 @@ public void willAbortBatchUpdateOnNullPointerExceptionDueToNoIdInRequest() throw public void cannotInjectSqlThroughRequestId() throws Exception { UUID itemId = UUID.randomUUID(); - JsonObject firstRequest = createRequestForItemAtPosition(itemId, 1); + JsonObject firstRequest = createRequestAtPosition(itemId, null, 1); JsonObject firstRequestCopy = firstRequest.copy(); firstRequestCopy.put("id", "1'; DELETE FROM request where id::text is not '1"); @@ -219,6 +226,38 @@ public void cannotInjectSqlThroughRequestId() throws Exception { assertRequestsNotUpdated(itemId, firstRequest); } + @Test + public void shouldPublishKafkaEventWhenUpdateRequestPositionsInBatchForTheInstance() + throws Exception { + + UUID instanceId = UUID.randomUUID(); + JsonObject firstRequest = createRequestAtPosition(null, instanceId, 1); + JsonObject secondRequest = createRequestAtPosition(null, instanceId, 2); + + ReorderRequest firstReorderRequest = new ReorderRequest(firstRequest, 2); + ReorderRequest secondReorderRequest = new ReorderRequest(secondRequest, 1); + + reorderRequests(firstReorderRequest, secondReorderRequest); + + JsonObject requestsForInstanceReply = getAllRequestsForInstance(instanceId); + assertThat(requestsForInstanceReply.getInteger("totalRecords"), is(2)); + JsonArray requestsFromDb = requestsForInstanceReply.getJsonArray("requests"); + assertThat(requestsFromDb.size(), is(2)); + List requestsSorted = requestsFromDb.stream() + .map(JsonObject.class::cast) + .sorted(Comparator.comparingInt(obj -> obj.getInteger("position"))) + .toList(); + String firstRequestId = firstRequest.getString("id"); + String secondRequestId = secondRequest.getString("id"); + assertThat(requestsSorted.get(0).getInteger("position"), is(1)); + assertThat(requestsSorted.get(1).getInteger("position"), is(2)); + assertThat(requestsSorted.get(0).getString("id"), is(secondRequestId)); + assertThat(requestsSorted.get(1).getString("id"), is(firstRequestId)); + + assertRequestQueueReorderingEvent(instanceId.toString(), + requestsSorted.get(1).getString("itemId"), List.of(firstRequestId, secondRequestId), TITLE); + } + private JsonObject getAllRequestsForItem(UUID itemId) throws Exception { CompletableFuture getRequestsCompleted = new CompletableFuture<>(); @@ -228,10 +267,30 @@ private JsonObject getAllRequestsForItem(UUID itemId) throws Exception { return getRequestsCompleted.get(5, TimeUnit.SECONDS).getJson(); } - private JsonObject createRequestForItemAtPosition(UUID itemId, int position) throws Exception { - JsonObject request = createEntity( - new RequestRequestBuilder() + private JsonObject getAllRequestsForInstance(UUID instanceId) throws Exception { + CompletableFuture getRequestsCompleted = new CompletableFuture<>(); + + client.get(requestStorageUrl() + String.format("?query=instanceId==%s", instanceId), + TENANT_ID, ResponseHandler.json(getRequestsCompleted)); + + return getRequestsCompleted.get(5, TimeUnit.SECONDS).getJson(); + } + + private JsonObject createRequestAtPosition(UUID itemId, UUID instanceId, int position) + throws Exception { + + RequestRequestBuilder requestBuilder = null; + if (instanceId != null) { + requestBuilder = new RequestRequestBuilder() + .withInstanceId(instanceId) + .withRequestLevel("Title"); + } else { + requestBuilder = new RequestRequestBuilder() .withItemId(itemId) + .withRequestLevel("Item"); + } + JsonObject request = createEntity( + requestBuilder .withPosition(position) .recall() .toHoldShelf() @@ -240,7 +299,11 @@ private JsonObject createRequestForItemAtPosition(UUID itemId, int position) thr requestStorageUrl() ).getJson(); - assertThat(request.getString("itemId"), is(itemId.toString())); + if (itemId != null) { + assertThat(request.getString("itemId"), is(itemId.toString())); + } else { + assertThat(request.getString("instanceId"), is(instanceId.toString())); + } assertThat(request.getInteger("position"), is(position)); return request; diff --git a/src/test/java/org/folio/rest/api/RequestsApiTest.java b/src/test/java/org/folio/rest/api/RequestsApiTest.java index 4137de0d2..cc5fb2578 100644 --- a/src/test/java/org/folio/rest/api/RequestsApiTest.java +++ b/src/test/java/org/folio/rest/api/RequestsApiTest.java @@ -1961,6 +1961,46 @@ public void cannotCreateRequestWithoutStatus() ))); } + @Test + public void canCreateRequestWithEcsRequestPhase() throws MalformedURLException, + ExecutionException, InterruptedException, TimeoutException { + + JsonObject representation = createEntity( + new RequestRequestBuilder() + .page() + .primary() + .withId(UUID.randomUUID()) + .create(), + requestStorageUrl()).getJson(); + assertThat(representation.getString("ecsRequestPhase"), is("Primary")); + + representation = createEntity( + new RequestRequestBuilder() + .page() + .secondary() + .withId(UUID.randomUUID()) + .create(), + requestStorageUrl()).getJson(); + assertThat(representation.getString("ecsRequestPhase"), is("Secondary")); + } + + @Test + public void shouldReturn400IfInvalidEcsRequestPhase() throws MalformedURLException, + ExecutionException, InterruptedException, TimeoutException { + + var request = new RequestRequestBuilder() + .page() + .withEcsRequestPhase("Invalid") + .withId(UUID.randomUUID()) + .create(); + + CompletableFuture createCompleted = new CompletableFuture<>(); + client.post(requestStorageUrl(), request, TENANT_ID, ResponseHandler.json(createCompleted)); + + assertThat(createCompleted.get(5, TimeUnit.SECONDS).getStatusCode(), is(400)); + } + + private RequestDto.RequestDtoBuilder holdShelfOpenRequest() { return RequestDto.builder() .requesterId(UUID.randomUUID().toString()) diff --git a/src/test/java/org/folio/rest/api/StaffSlipsApiTest.java b/src/test/java/org/folio/rest/api/StaffSlipsApiTest.java index 1810d9b79..71baffd25 100644 --- a/src/test/java/org/folio/rest/api/StaffSlipsApiTest.java +++ b/src/test/java/org/folio/rest/api/StaffSlipsApiTest.java @@ -38,8 +38,11 @@ public class StaffSlipsApiTest extends ApiTests { private static final String ID_KEY = "id"; private static final String ACTIVE_KEY = "active"; private static final String NAME_KEY = "name"; - private static final String DESCRIPTON_KEY = "description"; + private static final String DESCRIPTION_KEY = "description"; private static final String TEMPLATE_KEY = "template"; + private static final String [] STAFF_SLIP_NAMES = {"Hold", "Transit", "Request delivery", "Pick slip", + "Search slip (Hold requests)", "Transit (mediated requests)", "Due date receipt"}; + private static final String STAFF_SLIPS_KEY = "staffSlips"; private static AtomicBoolean isRefTestDone = new AtomicBoolean(false); @@ -66,10 +69,9 @@ private void canGetStaffSlipReferenceData() assertThat(getResponse.getStatusCode(), is(HttpURLConnection.HTTP_OK)); - JsonArray slipsJsonArray = getResponse.getJson().getJsonArray("staffSlips"); + JsonArray slipsJsonArray = getResponse.getJson().getJsonArray(STAFF_SLIPS_KEY); Object [] names = slipsJsonArray.stream().map(o -> ((JsonObject) o).getString(NAME_KEY)).toArray(); - assertThat(names, arrayContainingInAnyOrder("Hold", "Transit", "Request delivery", "Pick slip", - "Search slip (Hold requests)","Due date receipt")); + assertThat(names, arrayContainingInAnyOrder(STAFF_SLIP_NAMES)); } /* Begin Tests */ @@ -86,7 +88,7 @@ public void canCreateAStaffSlip() assertThat(creationResponse.getJson().getString(ID_KEY), notNullValue()); assertThat(creationResponse.getJson().getBoolean(ACTIVE_KEY), is(true)); assertThat(creationResponse.getJson().getString(NAME_KEY), is(TEST_STAFF_SLIP_1_NAME)); - assertThat(creationResponse.getJson().getString(DESCRIPTON_KEY), is(TEST_STAFF_SLIP_1_DESCRIPTION)); + assertThat(creationResponse.getJson().getString(DESCRIPTION_KEY), is(TEST_STAFF_SLIP_1_DESCRIPTION)); assertThat(creationResponse.getJson().getString(TEMPLATE_KEY), is(TEST_STAFF_SLIP_1_Template)); } @@ -197,7 +199,7 @@ public void canUpdateStaffSlipById() JsonResponse getResponse = getCompleted.get(5, TimeUnit.SECONDS); assertThat(putReponse.getStatusCode(), is(HttpURLConnection.HTTP_NO_CONTENT)); - assertThat(getResponse.getJson().getString(DESCRIPTON_KEY), is(TEST_STAFF_SLIP_1_DESCRIPTION_ALTERNATE)); + assertThat(getResponse.getJson().getString(DESCRIPTION_KEY), is(TEST_STAFF_SLIP_1_DESCRIPTION_ALTERNATE)); } diff --git a/src/test/java/org/folio/rest/api/migration/StaffSlipsMigrationTestBase.java b/src/test/java/org/folio/rest/api/migration/StaffSlipsMigrationTestBase.java index 632848371..7a5be5962 100644 --- a/src/test/java/org/folio/rest/api/migration/StaffSlipsMigrationTestBase.java +++ b/src/test/java/org/folio/rest/api/migration/StaffSlipsMigrationTestBase.java @@ -13,25 +13,30 @@ import io.vertx.core.json.JsonObject; public class StaffSlipsMigrationTestBase extends MigrationTestBase { - public static final String TEMPLATE = "

"; + private static final String TEMPLATE = "

"; + private static final String ID_KEY = "id"; + private static final String NAME_KEY = "name"; + private static final String ACTIVE_KEY = "active"; + private static final String TEMPLATE_KEY = "template"; + private static final String STORAGE_URL = "/staff-slips-storage/staff-slips"; JsonObject getRecordById(JsonArray collection, String id) { return collection.stream() .map(index -> (JsonObject) index) - .filter(request -> StringUtils.equals(request.getString("id"), id)) + .filter(request -> StringUtils.equals(request.getString(ID_KEY), id)) .findFirst().orElse(null); } void assertStaffSlip(JsonObject staffSlip, String expectedId, String expectedName) { - assertThat(staffSlip.getString("id"), is(expectedId)); - assertThat(staffSlip.getString("name"), is(expectedName)); - assertThat(staffSlip.getBoolean("active"), is(true)); - assertThat(staffSlip.getString("template"), is(TEMPLATE)); + assertThat(staffSlip.getString(ID_KEY), is(expectedId)); + assertThat(staffSlip.getString(NAME_KEY), is(expectedName)); + assertThat(staffSlip.getBoolean(ACTIVE_KEY), is(true)); + assertThat(staffSlip.getString(TEMPLATE_KEY), is(TEMPLATE)); } URL staffSlipsStorageUrl(String subPath) throws MalformedURLException { - return StorageTestSuite.storageUrl("/staff-slips-storage/staff-slips" + subPath); + return StorageTestSuite.storageUrl(STORAGE_URL + subPath); } } diff --git a/src/test/java/org/folio/rest/api/migration/StaffSlipsTransitMediatedRequestsMigrationScriptTest.java b/src/test/java/org/folio/rest/api/migration/StaffSlipsTransitMediatedRequestsMigrationScriptTest.java new file mode 100644 index 000000000..aa510fbe3 --- /dev/null +++ b/src/test/java/org/folio/rest/api/migration/StaffSlipsTransitMediatedRequestsMigrationScriptTest.java @@ -0,0 +1,49 @@ +package org.folio.rest.api.migration; + +import static org.junit.Assert.assertThat; + +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import org.folio.rest.api.StorageTestSuite; +import org.folio.rest.support.JsonResponse; +import org.folio.rest.support.ResponseHandler; +import org.hamcrest.core.Is; +import org.junit.Before; +import org.junit.Test; + +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; + +public class StaffSlipsTransitMediatedRequestsMigrationScriptTest extends StaffSlipsMigrationTestBase{ + + private static final String STAFF_SLIP_ID = "e6e29ec1-1a76-4913-bbd3-65f4ffd94e04"; + private static final String SCRIPT_NAME = "add_staff_slips_transit_mediated_requests.sql"; + private static final String STAFF_SLIPS_KEY = "staffSlips"; + private static final String STAFF_SLIPS_SUB_PATH = ""; + private static final String STAFF_SLIP_NAME = "Transit (mediated requests)"; + private static final int TIMEOUT_VALUE = 5; + + @Before + public void beforeEach() throws MalformedURLException { + StorageTestSuite.deleteAll(staffSlipsStorageUrl(STAFF_SLIPS_SUB_PATH)); + } + + @Test + public void canMigrateStaffSlips() throws Exception { + executeMultipleSqlStatements(loadScript(SCRIPT_NAME)); + CompletableFuture getCompleted = new CompletableFuture<>(); + client.get(staffSlipsStorageUrl(STAFF_SLIPS_SUB_PATH), StorageTestSuite.TENANT_ID, + ResponseHandler.json(getCompleted)); + JsonResponse getResponse = getCompleted.get(TIMEOUT_VALUE, TimeUnit.SECONDS); + + assertThat(getResponse.getStatusCode(), Is.is(HttpURLConnection.HTTP_OK)); + + JsonArray slipsJsonArray = getResponse.getJson().getJsonArray(STAFF_SLIPS_KEY); + JsonObject staffSlips = getRecordById(slipsJsonArray, STAFF_SLIP_ID); + + assertStaffSlip(staffSlips, STAFF_SLIP_ID, STAFF_SLIP_NAME); + } +} diff --git a/src/test/java/org/folio/rest/support/builders/RequestRequestBuilder.java b/src/test/java/org/folio/rest/support/builders/RequestRequestBuilder.java index a6c86ee54..4a7e8335d 100644 --- a/src/test/java/org/folio/rest/support/builders/RequestRequestBuilder.java +++ b/src/test/java/org/folio/rest/support/builders/RequestRequestBuilder.java @@ -53,6 +53,7 @@ public class RequestRequestBuilder extends JsonBuilder { private final UUID holdingsRecordId; private final SearchIndex searchIndex; private final String itemLocationCode; + private final String ecsRequestPhase; public RequestRequestBuilder() { this(UUID.randomUUID(), @@ -81,6 +82,7 @@ public RequestRequestBuilder() { null, UUID.randomUUID(), null, + null, null); } @@ -103,6 +105,7 @@ public JsonObject create() { put(request, "requestExpirationDate", this.requestExpirationDate); put(request, "holdShelfExpirationDate", this.holdShelfExpirationDate); put(request, "pickupServicePointId", this.pickupServicePointId); + put(request, "ecsRequestPhase", this.ecsRequestPhase); if (this.itemSummary != null) { final JsonObject item = new JsonObject(); @@ -211,6 +214,7 @@ public RequestRequestBuilder withNoId() { this.patronComments, this.holdingsRecordId, this.searchIndex, + this.ecsRequestPhase, this.itemLocationCode); } @@ -255,6 +259,7 @@ public RequestRequestBuilder withItem(RequestItemSummary item) { this.patronComments, this.holdingsRecordId, this.searchIndex, + this.ecsRequestPhase, this.itemLocationCode); } @@ -291,6 +296,7 @@ public RequestRequestBuilder withRequester( this.patronComments, this.holdingsRecordId, this.searchIndex, + this.ecsRequestPhase, this.itemLocationCode); } @@ -326,6 +332,7 @@ public RequestRequestBuilder withRequester( this.patronComments, this.holdingsRecordId, this.searchIndex, + this.ecsRequestPhase, this.itemLocationCode); } @@ -361,6 +368,7 @@ public RequestRequestBuilder withProxy( this.patronComments, this.holdingsRecordId, this.searchIndex, + this.ecsRequestPhase, this.itemLocationCode); } public RequestRequestBuilder withNoPosition() { @@ -386,4 +394,12 @@ private class PatronSummary { } } + public RequestRequestBuilder primary() { + return withEcsRequestPhase("Primary"); + } + + public RequestRequestBuilder secondary() { + return withEcsRequestPhase("Secondary"); + } + } diff --git a/src/test/java/org/folio/rest/support/kafka/FakeKafkaConsumer.java b/src/test/java/org/folio/rest/support/kafka/FakeKafkaConsumer.java index da59490dc..6f5dd0e5e 100644 --- a/src/test/java/org/folio/rest/support/kafka/FakeKafkaConsumer.java +++ b/src/test/java/org/folio/rest/support/kafka/FakeKafkaConsumer.java @@ -27,6 +27,7 @@ public final class FakeKafkaConsumer { private static final String REQUEST_TOPIC_NAME = "folio.test_tenant.circulation.request"; private static final String CHECKIN_TOPIC_NAME = "folio.test_tenant.circulation.check-in"; private static final String CIRCULATION_RULES_TOPIC_NAME = "folio.test_tenant.circulation.rules"; + private static final String REQUEST_QUEUE_REORDERING_TOPIC_NAME = "folio.test_tenant.circulation.request-queue-reordering"; private static final Map>> loanEvents = new ConcurrentHashMap<>(); @@ -36,19 +37,21 @@ public final class FakeKafkaConsumer { new ConcurrentHashMap<>(); private static final Map>> circulationRulesEvents = new ConcurrentHashMap<>(); - + private static final Map>> requestQueueReorderingEvents = + new ConcurrentHashMap<>(); private static final Map>>> topicToEvents = Map.of( LOAN_TOPIC_NAME, loanEvents, REQUEST_TOPIC_NAME, requestEvents, CHECKIN_TOPIC_NAME, checkInEvents, - CIRCULATION_RULES_TOPIC_NAME, circulationRulesEvents + CIRCULATION_RULES_TOPIC_NAME, circulationRulesEvents, + REQUEST_QUEUE_REORDERING_TOPIC_NAME, requestQueueReorderingEvents ); public FakeKafkaConsumer consume(Vertx vertx) { final KafkaConsumer consumer = create(vertx, consumerProperties()); consumer.subscribe(Set.of(LOAN_TOPIC_NAME, REQUEST_TOPIC_NAME, CHECKIN_TOPIC_NAME, - CIRCULATION_RULES_TOPIC_NAME)); + CIRCULATION_RULES_TOPIC_NAME, REQUEST_QUEUE_REORDERING_TOPIC_NAME)); consumer.handler(message -> { var recordEvents = topicToEvents.get(message.topic()); @@ -69,6 +72,7 @@ public static void removeAllEvents() { requestEvents.clear(); checkInEvents.clear(); circulationRulesEvents.clear(); + requestQueueReorderingEvents.clear(); } public static int getAllPublishedLoanCount() { @@ -94,6 +98,13 @@ public static Collection> getCirculation .orElseGet(Collections::emptyList); } + public static Collection> getRequestQueueReorderingEvents() { + return requestQueueReorderingEvents.values() + .stream() + .findFirst() + .orElseGet(Collections::emptyList); + } + public static KafkaConsumerRecord getFirstLoanEvent(String loanId) { return getFirstEvent(getLoanEvents(loanId)); } @@ -126,6 +137,10 @@ public static KafkaConsumerRecord getFirstCheckInEvent(Strin return getFirstEvent(getCheckInEvents(checkInId)); } + public static KafkaConsumerRecord getFirstRequestQueueReorderingEvent() { + return getFirstEvent(getRequestQueueReorderingEvents()); + } + private static KafkaConsumerRecord getFirstEvent( Collection> events) { diff --git a/src/test/java/org/folio/rest/support/matchers/DomainEventAssertions.java b/src/test/java/org/folio/rest/support/matchers/DomainEventAssertions.java index 5c3d9ba8d..f3fda249c 100644 --- a/src/test/java/org/folio/rest/support/matchers/DomainEventAssertions.java +++ b/src/test/java/org/folio/rest/support/matchers/DomainEventAssertions.java @@ -11,12 +11,14 @@ import static org.folio.rest.support.kafka.FakeKafkaConsumer.getCheckInEvents; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getCirculationRulesEvents; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getFirstLoanEvent; +import static org.folio.rest.support.kafka.FakeKafkaConsumer.getFirstRequestQueueReorderingEvent; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getLastCheckInEvent; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getLastCirculationRulesEvent; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getLastLoanEvent; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getLastRequestEvent; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getLoanEvents; import static org.folio.rest.support.kafka.FakeKafkaConsumer.getRequestEvents; +import static org.folio.rest.support.kafka.FakeKafkaConsumer.getRequestQueueReorderingEvents; import static org.folio.rest.support.matchers.UUIDMatchers.hasUUIDFormat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; @@ -31,9 +33,11 @@ import org.awaitility.Awaitility; import org.awaitility.core.ConditionFactory; +import org.folio.rest.jaxrs.model.RequestQueueReordering; import org.folio.service.event.DomainEventType; import io.vertx.core.MultiMap; +import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.kafka.client.consumer.KafkaConsumerRecord; import io.vertx.kafka.client.producer.KafkaHeader; @@ -108,6 +112,20 @@ public static void assertCreateEventForRequest(JsonObject request) { assertCreateEvent(getLastRequestEvent(requestId), request); } + public static void assertRequestQueueReorderingEvent(String instanceId, String itemId, + List requestIds, RequestQueueReordering.RequestLevel requestLevel) { + + await().until(() -> getRequestQueueReorderingEvents().size(), greaterThan(0)); + + JsonObject payload = new JsonObject() + .put("instanceId", instanceId) + .put("itemId", itemId) + .put("requestLevel", requestLevel.value()) + .put("requestIds", new JsonArray(requestIds)); + + assertCreateEvent(getFirstRequestQueueReorderingEvent(), payload); + } + public static void assertNoRequestEvent(String requestId) { await().during(1, SECONDS) .until(() -> getRequestEvents(requestId), is(empty())); diff --git a/src/test/java/org/folio/service/kafka/topic/KafkaAdminClientServiceTest.java b/src/test/java/org/folio/service/kafka/topic/KafkaAdminClientServiceTest.java index e5b63c190..574ecd6eb 100644 --- a/src/test/java/org/folio/service/kafka/topic/KafkaAdminClientServiceTest.java +++ b/src/test/java/org/folio/service/kafka/topic/KafkaAdminClientServiceTest.java @@ -43,7 +43,8 @@ public class KafkaAdminClientServiceTest { "folio.foo-tenant.circulation.loan", "folio.foo-tenant.circulation.check-in", "folio.foo-tenant.circulation.rules", - "folio.foo-tenant.circulation.circulation-settings" + "folio.foo-tenant.circulation.circulation-settings", + "folio.foo-tenant.circulation.request-queue-reordering" ); private KafkaAdminClient mockClient;