Skip to content

Commit

Permalink
[MODORDERS-1209]. Fix MockServer handleGetPieces from interfering
Browse files Browse the repository at this point in the history
  • Loading branch information
BKadirkhodjaev committed Dec 5, 2024
1 parent 836a422 commit 5d6596b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 35 deletions.
29 changes: 21 additions & 8 deletions src/main/java/org/folio/service/claiming/ClaimingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;

import static java.util.stream.Collectors.collectingAndThen;
Expand Down Expand Up @@ -55,6 +56,7 @@ public class ClaimingService {
private static final String CANNOT_RETRIEVE_CONFIG_ENTRIES = "Cannot retrieve config entries";
private static final String CANNOT_GROUP_PIECES_BY_VENDOR_MESSAGE = "Cannot group pieces by vendor";
private static final String CANNOT_CREATE_JOBS_AND_UPDATE_PIECES = "Cannot create jobs and update pieces";
private static final String CANNOT_FIND_A_PIECE_BY_ID = "Cannot find a piece by '%s' id";

private final ConfigurationEntriesCache configurationEntriesCache;
private final PieceStorageService pieceStorageService;
Expand Down Expand Up @@ -112,30 +114,40 @@ private Future<Map<String, List<String>>> groupPieceIdsByVendorId(List<String> p
logger.info("groupPieceIdsByVendorId:: No pieces are grouped by vendor, pieceIds is empty");
return Future.succeededFuture();
}
logger.info("groupPieceIdsByVendorId:: Grouping pieces by vendor");
logger.info("groupPieceIdsByVendorId:: Grouping pieces by vendor, pieceIds count: {}", pieceIds.size());
return pieceStorageService.getPiecesByIds(pieceIds, requestContext)
.compose(pieces -> {
if (CollectionUtils.isEmpty(pieces)) {
logger.info("groupPieceIdsByVendorId:: No pieces are found by piece ids, pieceIds: {}", pieceIds);
return Future.succeededFuture();
}
var uniquePiecePoLinePairs = pieces.stream()
.filter(Objects::nonNull).filter(piece -> Objects.nonNull(piece.getId()) & Objects.nonNull(piece.getPoLineId()))
.map(piece -> Pair.of(piece.getPoLineId(), piece.getId())).distinct()
.toList();
return collectResultsOnSuccess(createPieceIdByVendorFutures(uniquePiecePoLinePairs, requestContext))
logger.info("groupPieceIdsByVendorId:: Prepared unique piece-poLine pairs, pairs: {}", uniquePiecePoLinePairs);
return collectResultsOnSuccess(createPieceIdByVendorFutures(pieces, uniquePiecePoLinePairs, requestContext))
.map(ClaimingService::transformAndGroupPieceIdsByVendorId);
});
}

private List<Future<Pair<String, String>>> createPieceIdByVendorFutures(List<Pair<String, String>> uniquePiecePoLinePairs, RequestContext requestContext) {
private List<Future<Pair<String, String>>> createPieceIdByVendorFutures(List<Piece> pieces, List<Pair<String, String>> uniquePiecePoLinePairs,
RequestContext requestContext) {
var pieceIdByVendorIdFutures = new ArrayList<Future<Pair<String, String>>>();
uniquePiecePoLinePairs.forEach(piecePoLinePairs -> {
var pieceIdByVendorIdFuture = pieceStorageService.getPieceById(piecePoLinePairs.getRight(), requestContext)
.compose(piece -> createVendorPiecePair(piecePoLinePairs, piece, requestContext));
var foundPiece = pieces.stream()
.filter(Objects::nonNull).filter(piece -> Objects.nonNull(piece.getId())).filter(piece -> piece.getId().equals(piecePoLinePairs.getRight()))
.findFirst().orElseThrow(() -> new NoSuchElementException(String.format(CANNOT_FIND_A_PIECE_BY_ID, piecePoLinePairs.getRight())));
var pieceIdByVendorIdFuture = createVendorPiecePair(piecePoLinePairs, foundPiece, requestContext);
if (Objects.nonNull(pieceIdByVendorIdFuture)) {
pieceIdByVendorIdFutures.add(pieceIdByVendorIdFuture);
}
});
return pieceIdByVendorIdFutures;
}

private Future<Pair<String, String>> createVendorPiecePair(Pair<String, String> piecePoLinePairs, Piece piece, RequestContext requestContext) {
private Future<Pair<String, String>> createVendorPiecePair(Pair<String, String> piecePoLinePairs,
Piece piece, RequestContext requestContext) {
if (Objects.nonNull(piece) && !piece.getReceivingStatus().equals(Piece.ReceivingStatus.LATE)) {
logger.info("createVendorPiecePair:: Ignoring processing of a piece not in LATE state, piece id: {}", piece.getId());
return Future.succeededFuture();
Expand Down Expand Up @@ -166,7 +178,7 @@ private Future<ClaimingResults> createJobsByVendor(JsonObject config, Map<String
return collectResultsOnSuccess(createUpdatePiecesAndJobFutures(config, pieceIdsByVendorId, requestContext))
.map(updatedPieceLists -> {
if (CollectionUtils.isEmpty(updatedPieceLists)) {
logger.info("createJobsByVendor:: No pieces were processes for claiming");
logger.info("createJobsByVendor:: No pieces were processed for claiming");
return new ClaimingResults().withClaimingPieceResults(createErrorClaimingResults(pieceIdsByVendorId, CANNOT_CREATE_JOBS_AND_UPDATE_PIECES));
}
var successClaimingPieceResults = createSuccessClaimingResults(updatedPieceLists);
Expand All @@ -175,7 +187,8 @@ private Future<ClaimingResults> createJobsByVendor(JsonObject config, Map<String
});
}

private List<Future<List<String>>> createUpdatePiecesAndJobFutures(JsonObject config, Map<String, List<String>> pieceIdsByVendorId, RequestContext requestContext) {
private List<Future<List<String>>> createUpdatePiecesAndJobFutures(JsonObject config, Map<String, List<String>> pieceIdsByVendorId,
RequestContext requestContext) {
var updatePiecesAndJobFutures = new ArrayList<Future<List<String>>>();
pieceIdsByVendorId.forEach((vendorId, pieceIds) -> config.stream()
.filter(entry -> isExportTypeClaimsAndCorrectVendorId(vendorId, entry) && Objects.nonNull(entry.getValue()))
Expand Down
1 change: 1 addition & 0 deletions src/test/java/org/folio/TestConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ private TestConstants() {}
public static final String NON_EXIST_HOLDINGS_SOURCE_TENANT = "nonExistHoldingsSource";
public static final String COMPOSITE_PO_LINES_PREFIX = "compositePoLines[0].";
public static final String OKAPI_URL = "X-Okapi-Url";
public static final String OKAPI_TENANT = "X-Okapi-Tenant";

public static final Header INSTANCE_TYPE_CONTAINS_CODE_AS_INSTANCE_STATUS_TENANT_HEADER = new Header(OKAPI_HEADER_TENANT, INSTANCE_TYPE_CONTAINS_CODE_AS_INSTANCE_STATUS_TENANT);
public static final Header NON_EXIST_INSTANCE_STATUS_TENANT_HEADER = new Header(OKAPI_HEADER_TENANT, NON_EXIST_INSTANCE_STATUS_TENANT);
Expand Down
41 changes: 31 additions & 10 deletions src/test/java/org/folio/rest/impl/ClaimingApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.restassured.http.Header;
import io.vertx.core.json.JsonObject;
import io.vertx.junit5.VertxExtension;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.ApiTestSuite;
Expand All @@ -11,13 +12,17 @@
import org.folio.rest.jaxrs.model.ClaimingPieceResult;
import org.folio.rest.jaxrs.model.ClaimingResults;
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.model.PieceCollection;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
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 java.util.Collection;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
Expand All @@ -36,10 +41,12 @@
import static org.folio.TestUtils.getMinimalOrder;
import static org.folio.TestUtils.getMockAsJson;
import static org.folio.orders.utils.ResourcePathResolver.ORGANIZATION_STORAGE;
import static org.folio.orders.utils.ResourcePathResolver.PIECES_STORAGE;
import static org.folio.orders.utils.ResourcePathResolver.PO_LINES_STORAGE;
import static org.folio.orders.utils.ResourcePathResolver.PURCHASE_ORDER_STORAGE;
import static org.folio.rest.impl.MockServer.BASE_MOCK_DATA_PATH;
import static org.folio.rest.impl.MockServer.ORGANIZATION_COLLECTION;
import static org.folio.rest.impl.MockServer.PIECES_COLLECTION;
import static org.folio.rest.impl.MockServer.PO_LINES_COLLECTION;
import static org.folio.rest.impl.MockServer.addMockEntry;
import static org.folio.rest.impl.MockServer.getDataExportSpringJobCreations;
Expand All @@ -49,6 +56,8 @@
import static org.folio.rest.impl.MockServer.getPieceUpdates;
import static org.folio.rest.impl.MockServer.getPoLineSearches;
import static org.folio.rest.impl.MockServer.getPurchaseOrderRetrievals;
import static org.folio.rest.jaxrs.model.ClaimingPieceResult.Status.FAILURE;
import static org.folio.rest.jaxrs.model.ClaimingPieceResult.Status.SUCCESS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
Expand All @@ -57,13 +66,15 @@
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;

@ExtendWith(VertxExtension.class)
public class ClaimingApiTest {

private static final Logger logger = LogManager.getLogger();
private static boolean runningOnOwn;

private static final String ORGANIZATIONS_KEY = "organizations";
private static final String PO_LINES_KEY = "poLines";
private static final String PIECES_KEY = "pieces";
private static final String CLAIMING_MOCK_DATA_FOLDER = "claiming/";

@BeforeAll
Expand All @@ -88,13 +99,11 @@ static void after() {
}

private static Stream<Arguments> testPostOrdersClaimArgs() {
var payloadFile = "send-claims-1-piece-1-vendor-1-job.json";
var mockHitDto = new MockHitDto(2, 2, 2, 1, 1, 1, 1, 1);
return Stream.of(
Arguments.of("One piece One vendor One Job", 0, 17,
new MockHitDto(3, 2, 2, 1, 1, 1, 1, 1),
"send-claims-1-piece-1-vendor-1-job.json", EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10_CLAIMS, ClaimingPieceResult.Status.SUCCESS),
Arguments.of("One piece One vendor No Job", 0, 17,
null,
"send-claims-1-piece-1-vendor-1-job.json", EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, ClaimingPieceResult.Status.FAILURE)
Arguments.of("One piece One vendor One Job", 0, 17, 69, mockHitDto, payloadFile, EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10_CLAIMS, SUCCESS),
Arguments.of("One piece One vendor No Job", 0, 17, 69, null, payloadFile, EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, FAILURE)
);
}

Expand Down Expand Up @@ -125,7 +134,7 @@ public MockHitDto(int pieceSearches, int polSearches, int purchaseOrderRetrieval

@ParameterizedTest
@MethodSource("testPostOrdersClaimArgs")
void testPostOrdersClaim(String name, int vendorIdx, int polIdx, MockHitDto dto,
void testPostOrdersClaim(String name, int vendorIdx, int poLineIdx, int pieceIdx, MockHitDto dto,
String payloadFile, Header header, ClaimingPieceResult.Status expectedStatus) {
logger.info("Testing postOrdersClaim, name: {}", name);

Expand All @@ -134,21 +143,33 @@ void testPostOrdersClaim(String name, int vendorIdx, int polIdx, MockHitDto dto,
.mapTo(Organization.class);
var poLine = getMockAsJson(PO_LINES_COLLECTION)
.getJsonArray(PO_LINES_KEY)
.getJsonObject(polIdx)
.getJsonObject(poLineIdx)
.mapTo(CompositePoLine.class);
var purchaseOrder = getMinimalOrder(poLine)
.withVendor(organization.getId());
var piece = getMockAsJson(PIECES_COLLECTION)
.getJsonArray(PIECES_KEY)
.getJsonObject(pieceIdx)
.mapTo(Piece.class);

addMockEntry(ORGANIZATION_STORAGE, organization);
addMockEntry(PURCHASE_ORDER_STORAGE, purchaseOrder);
addMockEntry(PO_LINES_STORAGE, poLine);
addMockEntry(PIECES_STORAGE, piece);

var mockDataPath = BASE_MOCK_DATA_PATH + CLAIMING_MOCK_DATA_FOLDER + payloadFile;
var request = JsonObject.mapFrom(getMockAsJson(mockDataPath).mapTo(ClaimingCollection.class)).encode();
var response = verifyPostResponse(ORDERS_CLAIMING_ENDPOINT, request, prepareHeaders(header), APPLICATION_JSON, CREATED.code())
.as(ClaimingResults.class);

var pieceSearches = getPieceSearches();
// Filter out any dummy pieces without ids that are loaded from other tests
var pieceSearches = getPieceSearches().stream()
.map(JsonObject::mapFrom).map(json -> json.mapTo(PieceCollection.class))
.map(collection -> collection.getPieces().stream()
.filter(entry -> Objects.nonNull(entry.getId())).filter(entry -> entry.getId().equals(piece.getId()))
.toList())
.flatMap(Collection::stream)
.toList();
var polSearches = getPoLineSearches();
var purchaseOrderRetrievals = getPurchaseOrderRetrievals();
var organizationSearches = getOrganizationSearches();
Expand Down Expand Up @@ -179,7 +200,7 @@ void testPostOrdersClaim(String name, int vendorIdx, int polIdx, MockHitDto dto,
.forEach(result -> {
assertThat(result.getPieceId(), not(nullValue()));
assertThat(result.getStatus(), is(expectedStatus));
if (expectedStatus == ClaimingPieceResult.Status.SUCCESS) {
if (expectedStatus == SUCCESS) {
assertThat(result.getError(), is(nullValue()));
} else {
assertThat(result.getError(), is(notNullValue()));
Expand Down
35 changes: 18 additions & 17 deletions src/test/java/org/folio/rest/impl/MockServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static org.folio.TestConstants.EMPTY_CONFIG_TENANT;
import static org.folio.TestConstants.EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_1;
import static org.folio.TestConstants.EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10;
import static org.folio.TestConstants.EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10_CLAIMS;
import static org.folio.TestConstants.ID;
import static org.folio.TestConstants.ID_BAD_FORMAT;
import static org.folio.TestConstants.ID_DOES_NOT_EXIST;
Expand All @@ -37,6 +38,7 @@
import static org.folio.TestConstants.NON_EXIST_INSTANCE_TYPE_TENANT_HEADER;
import static org.folio.TestConstants.NON_EXIST_LOAN_TYPE_TENANT;
import static org.folio.TestConstants.NON_EXIST_LOAN_TYPE_TENANT_HEADER;
import static org.folio.TestConstants.OKAPI_TENANT;
import static org.folio.TestConstants.PO_ID_GET_LINES_INTERNAL_SERVER_ERROR;
import static org.folio.TestConstants.PO_LINE_NUMBER_VALUE;
import static org.folio.TestConstants.PROTECTED_READ_ONLY_TENANT;
Expand Down Expand Up @@ -1200,18 +1202,16 @@ private void handleGetItemRecordsFromStorage(RoutingContext ctx) {

// Attempt to find POLine in mock server memory
List<JsonObject> itemsList = getRqRsEntries(HttpMethod.SEARCH, ITEM_RECORDS);
JsonObject items;
if (!itemsList.isEmpty()) {
JsonObject items = new JsonObject()
items = new JsonObject()
.put("items", itemsList)
.put(TOTAL_RECORDS, itemsList.size());

addServerRqRsData(HttpMethod.GET, ITEM_RECORDS, items);
serverResponse(ctx, 200, APPLICATION_JSON, items.encodePrettily());
} else {
JsonObject items = new JsonObject().put("items", new JsonArray());
addServerRqRsData(HttpMethod.GET, ITEM_RECORDS, items);
serverResponse(ctx, 200, APPLICATION_JSON, items.encodePrettily());
items = new JsonObject().put("items", new JsonArray());
}
addServerRqRsData(HttpMethod.GET, ITEM_RECORDS, items);
serverResponse(ctx, 200, APPLICATION_JSON, items.encodePrettily());
}

private void handleGetInventoryItemRecords(RoutingContext ctx) {
Expand Down Expand Up @@ -1258,7 +1258,7 @@ private void handleGetInventoryItemRecords(RoutingContext ctx) {
JsonObject item = (JsonObject) iterator.next();

if (!purchaseOrderLineIdentifier.equals(item.getString(ITEM_PURCHASE_ORDER_LINE_IDENTIFIER))
|| !holdingsRecordId.equals(item.getString(ITEM_HOLDINGS_RECORD_ID))) {
|| !holdingsRecordId.equals(item.getString(ITEM_HOLDINGS_RECORD_ID))) {
iterator.remove();
}
}
Expand Down Expand Up @@ -1902,11 +1902,7 @@ private void handleGetPieceById(RoutingContext ctx) {
String pieceId = ctx.request().getParam(ID);
logger.info("id: {}", pieceId);
try {
if ("dcd0ba36-b660-4751-b9fe-c8ac61ff6f99".equals(pieceId)) {
JsonObject data = new JsonObject(getMockData(PIECE_RECORDS_MOCK_DATA_PATH + String.format("pieceRecord-%s.json", pieceId)));
logger.info("handleGetPieceById custom, data: {}", data.encodePrettily());
serverResponse(ctx, HttpStatus.HTTP_OK.toInt(), APPLICATION_JSON, data.encodePrettily());
} else if (ID_DOES_NOT_EXIST.equals(pieceId)) {
if (ID_DOES_NOT_EXIST.equals(pieceId)) {
serverResponse(ctx, 404, APPLICATION_JSON, pieceId);
} else if (ID_FOR_INTERNAL_SERVER_ERROR.equals(pieceId)) {
serverResponse(ctx, 500, APPLICATION_JSON, pieceId);
Expand All @@ -1919,6 +1915,7 @@ private void handleGetPieceById(RoutingContext ctx) {
} else if (PIECE_POLINE_CONSISTENT_RECEIPT_STATUS_ID.equals(pieceId)) {
data = new JsonObject(getMockData(PIECE_RECORDS_MOCK_DATA_PATH + "pieceRecord-received-consistent-receipt-status-5b454292-6aaa-474f-9510-b59a564e0c8d2.json"));
} else {
// Load piece by id
data = new JsonObject(getMockData(PIECE_RECORDS_MOCK_DATA_PATH + String.format("pieceRecord-%s.json", pieceId)));
}
}
Expand All @@ -1941,8 +1938,8 @@ private void handleGetPieces(RoutingContext ctx) {
serverResponse(ctx, 500, APPLICATION_JSON, Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase());
} else {
PieceCollection pieces;
logger.info("handleGetPieces (all records), pieces present: {}", getMockEntries(PIECES_STORAGE, Piece.class).isPresent());
if (getMockEntries(PIECES_STORAGE, Piece.class).isPresent()) {
logger.info("handleGetPieces (all records), pieces already present: {}", getMockEntries(PIECES_STORAGE, Piece.class).isPresent());
if (!isTenantForClaiming(requestHeaders) && getMockEntries(PIECES_STORAGE, Piece.class).isPresent()) {
logger.info("handleGetPieces (all records)");
try {
List<Piece> piecesList = getMockEntries(PIECES_STORAGE, Piece.class).get();
Expand Down Expand Up @@ -1999,7 +1996,6 @@ private void handleGetPieces(RoutingContext ctx) {
}

pieces.setTotalRecords(pieces.getPieces().size());

} catch (Exception e) {
logger.info("handleGetPieces (with empty piece collection on exception)");
pieces = new PieceCollection();
Expand All @@ -2018,6 +2014,11 @@ private void handleGetPieces(RoutingContext ctx) {
}
}

// Prevent loading of unnecessary pieces from other tests for tenant that was made specifically for Claiming
private boolean isTenantForClaiming(MultiMap requestHeaders) {
return requestHeaders.get(OKAPI_TENANT.toLowerCase()).equals(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10_CLAIMS.getValue());
}

private void handleGetTitles(RoutingContext ctx) {
String query = StringUtils.trimToEmpty(ctx.request().getParam(QUERY));
addServerRqQuery(TITLES, query);
Expand Down Expand Up @@ -2418,7 +2419,7 @@ private void handleTransactionGetEntry(RoutingContext ctx) {
}

private void handleUserTenantsGetEntry(RoutingContext ctx) {
String body = new JsonObject().put("userTenants", org.assertj.core.util.Lists.emptyList()).encodePrettily();
String body = new JsonObject().put("userTenants", Collections.emptyList()).encodePrettily();
serverResponse(ctx, HttpStatus.HTTP_OK.toInt(), APPLICATION_JSON, body);
addServerRqRsData(HttpMethod.GET, USER_TENANTS_ENDPOINT, new JsonObject(body));
}
Expand Down

0 comments on commit 5d6596b

Please sign in to comment.