diff --git a/src/main/java/org/folio/rest/impl/PiecesAPI.java b/src/main/java/org/folio/rest/impl/PiecesAPI.java index 673be6e7..f6eb2ebd 100644 --- a/src/main/java/org/folio/rest/impl/PiecesAPI.java +++ b/src/main/java/org/folio/rest/impl/PiecesAPI.java @@ -114,11 +114,11 @@ public void putOrdersStoragePiecesById(String id, Piece entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - log.info("putOrdersStoragePiecesBatch:: Batch updating {} pieces: {}", piecesCollection.getPieces().size(), piecesCollection.getPieces()); + var piecesIds = extractEntityFields(piecesCollection.getPieces(), Piece::getId); + log.info("putOrdersStoragePiecesBatch:: Batch updating {} pieces: {}", piecesIds.size(), piecesIds); pgClient.withTrans(conn -> pieceService.updatePieces(piecesCollection.getPieces(), conn, TenantTool.tenantId(okapiHeaders)) .compose(updatedPieces -> auditOutboxService.savePiecesOutboxLog(conn, updatedPieces, PieceAuditEvent.Action.EDIT, okapiHeaders))) .onComplete(ar -> { - var piecesIds = extractEntityFields(piecesCollection.getPieces(), Piece::getId); if (ar.succeeded()) { log.info("putOrdersStoragePiecesBatch:: Successfully updated pieces: {}", piecesIds); auditOutboxService.processOutboxEventLogs(okapiHeaders); diff --git a/src/test/java/org/folio/StorageTestSuite.java b/src/test/java/org/folio/StorageTestSuite.java index 1d06568e..83cdfabf 100644 --- a/src/test/java/org/folio/StorageTestSuite.java +++ b/src/test/java/org/folio/StorageTestSuite.java @@ -42,6 +42,7 @@ import org.folio.rest.impl.EntititesCustomFieldsTest; import org.folio.rest.impl.HelperUtilsTest; import org.folio.rest.impl.OrdersAPITest; +import org.folio.rest.impl.PiecesAPITest; import org.folio.rest.impl.PoLineBatchAPITest; import org.folio.rest.impl.PoNumberTest; import org.folio.rest.impl.PurchaseOrderLineNumberTest; @@ -241,6 +242,8 @@ class EntitiesCrudTestNested extends EntitiesCrudTest {} @Nested class OrdersAPITestNested extends OrdersAPITest {} @Nested + class PiecesAPITestNested extends PiecesAPITest {} + @Nested class PoNumberTestNested extends PoNumberTest {} @Nested class PurchaseOrderLineApiTest extends PurchaseOrderLinesApiTest {} diff --git a/src/test/java/org/folio/rest/impl/PiecesAPITest.java b/src/test/java/org/folio/rest/impl/PiecesAPITest.java index 325d855b..fdcadf7b 100644 --- a/src/test/java/org/folio/rest/impl/PiecesAPITest.java +++ b/src/test/java/org/folio/rest/impl/PiecesAPITest.java @@ -3,42 +3,66 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.UUID; +import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.folio.CopilotGenerated; import org.folio.StorageTestSuite; import org.folio.event.AuditEventType; +import org.folio.rest.jaxrs.model.Piece; import org.folio.rest.jaxrs.model.PieceAuditEvent; +import org.folio.rest.jaxrs.model.PiecesCollection; import org.folio.rest.utils.TestData; import org.folio.rest.utils.TestEntities; -import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import io.restassured.http.Headers; import io.vertx.core.json.Json; import io.vertx.core.json.JsonObject; +@CopilotGenerated(partiallyGenerated = true) public class PiecesAPITest extends TestBase { private static final Logger log = LogManager.getLogger(); - @Test - void testPieceCreateUpdateEvents() throws MalformedURLException { - log.info("--- mod-orders-storage piece test: create / update event"); + private static final String PIECES_BATCH_ENDPOINT = "/orders-storage/pieces-batch"; - // given - String userId = UUID.randomUUID().toString(); - Headers headers = getDikuTenantHeaders(userId); - postData(TestEntities.PURCHASE_ORDER.getEndpoint(), getFile(TestData.PurchaseOrder.DEFAULT), headers).then().statusCode(201); - postData(TestEntities.PO_LINE.getEndpoint(), getFile(TestData.PoLine.DEFAULT), headers).then().statusCode(201); - postData(TestEntities.TITLES.getEndpoint(), getFile(TestData.Title.DEFAULT), headers).then().statusCode(201); + private String userId; + private String orderId; + private String poLineId; + private String titleId; + private Headers headers; + private List pieceIds; - callAuditOutboxApi(getDikuTenantHeaders(UUID.randomUUID().toString())); + @BeforeEach + void setUp() throws MalformedURLException { + userId = UUID.randomUUID().toString(); + orderId = UUID.randomUUID().toString(); + poLineId = UUID.randomUUID().toString(); + titleId = UUID.randomUUID().toString(); + headers = getDikuTenantHeaders(userId); + pieceIds = new ArrayList<>(); + prepareData(); + } + @AfterEach + void tearDown() throws MalformedURLException { + clearData(); + } + + @Test + void testPieceCreateUpdateEvents() throws MalformedURLException { + log.info("--- mod-orders-storage piece test: create / update event"); // when - JsonObject jsonPiece = new JsonObject(getFile(TestData.Piece.DEFAULT)); + pieceIds.add(UUID.randomUUID().toString()); + var jsonPiece = new JsonObject(getEntity(TestData.Piece.DEFAULT, pieceIds.get(0), "poLineId", poLineId, "titleId", titleId)); postData(TestEntities.PIECE.getEndpoint(), jsonPiece.toString(), headers) .then() .statusCode(201); @@ -56,4 +80,84 @@ void testPieceCreateUpdateEvents() throws MalformedURLException { checkPieceEventContent(events.get(1), PieceAuditEvent.Action.EDIT); } + @Test + void putOrdersStoragePiecesBatch_shouldUpdatePiecesSuccessfully() throws MalformedURLException { + log.info("--- mod-orders-storage piece test: batch update pieces"); + + // given + pieceIds.add(UUID.randomUUID().toString()); + pieceIds.add(UUID.randomUUID().toString()); + var jsonPiece1 = getEntity(TestData.Piece.DEFAULT, pieceIds.get(0), "poLineId", poLineId, "titleId", titleId); + var jsonPiece2 = getEntity(TestData.Piece.DEFAULT, pieceIds.get(1), "poLineId", poLineId, "titleId", titleId); + + postData(TestEntities.PIECE.getEndpoint(), jsonPiece1, headers).then().statusCode(201); + callAuditOutboxApi(headers); + + postData(TestEntities.PIECE.getEndpoint(), jsonPiece2, headers).then().statusCode(201); + callAuditOutboxApi(headers); + + // when + var piecesCollection = new PiecesCollection().withPieces(List.of( + new JsonObject(jsonPiece1).mapTo(Piece.class), + new JsonObject(jsonPiece2).mapTo(Piece.class) + )); + putData(PIECES_BATCH_ENDPOINT, Json.encode(piecesCollection), headers).then().statusCode(204); + callAuditOutboxApi(headers); + + // then + List events = StorageTestSuite.checkKafkaEventSent(TENANT_NAME, AuditEventType.ACQ_PIECE_CHANGED.getTopicName(), 4, userId); + assertEquals(4, events.size()); + checkPieceEventContent(events.get(0), PieceAuditEvent.Action.CREATE); + checkPieceEventContent(events.get(1), PieceAuditEvent.Action.CREATE); + checkPieceEventContent(events.get(2), PieceAuditEvent.Action.EDIT); + checkPieceEventContent(events.get(3), PieceAuditEvent.Action.EDIT); + } + + @Test + void putOrdersStoragePiecesBatch_shouldHandleEmptyPieceList() throws MalformedURLException { + log.info("--- mod-orders-storage piece test: batch update with empty piece list"); + // when + PiecesCollection piecesCollection = new PiecesCollection().withPieces(List.of()); + + putData(PIECES_BATCH_ENDPOINT, Json.encode(piecesCollection), headers) + .then() + .statusCode(204); + callAuditOutboxApi(headers); + + // then + List events = StorageTestSuite.checkKafkaEventSent(TENANT_NAME, AuditEventType.ACQ_PIECE_CHANGED.getTopicName(), 0, userId); + assertEquals(0, events.size()); + } + + private void prepareData() throws MalformedURLException { + postData(TestEntities.PURCHASE_ORDER.getEndpoint(), getEntity(TestData.PurchaseOrder.DEFAULT, orderId, "poNumber", "12345"), headers) + .then().statusCode(201); + postData(TestEntities.PO_LINE.getEndpoint(), getEntity(TestData.PoLine.DEFAULT, poLineId, "purchaseOrderId", orderId, "poLineNumber", "12345-1"), headers) + .then().statusCode(201); + postData(TestEntities.TITLES.getEndpoint(), getEntity(TestData.Title.DEFAULT, titleId, "poLineId", poLineId), headers) + .then().statusCode(201); + + callAuditOutboxApi(headers); + } + + private void clearData() throws MalformedURLException { + var entities = new ArrayList<>(pieceIds.stream().map(id -> Pair.of(TestEntities.PIECE, id)).toList()); + entities.addAll(List.of( + Pair.of(TestEntities.TITLES, titleId), + Pair.of(TestEntities.PO_LINE, poLineId), + Pair.of(TestEntities.PURCHASE_ORDER, orderId) + )); + for (var entry : entities) { + deleteData(entry.getLeft().getEndpointWithId(), entry.getRight()).then().statusCode(204); + } + } + + private String getEntity(String path, String id, String... replacements) { + var json = new JsonObject(getFile(path)).put("id", id); + for (int i = 0; i < replacements.length; i += 2) { + json.put(replacements[i], replacements[i + 1]); + } + return json.encode(); + } + } diff --git a/src/test/java/org/folio/rest/impl/TestBase.java b/src/test/java/org/folio/rest/impl/TestBase.java index 0033d2e1..84d81885 100644 --- a/src/test/java/org/folio/rest/impl/TestBase.java +++ b/src/test/java/org/folio/rest/impl/TestBase.java @@ -192,6 +192,14 @@ Response putData(String endpoint, String id, String input, Headers headers) thro .put(storageUrl(endpoint)); } + Response putData(String endpoint, String input, Headers headers) throws MalformedURLException { + return given() + .headers(headers) + .contentType(ContentType.JSON) + .body(input) + .put(storageUrl(endpoint)); + } + Response putData(String endpoint, String id, String input) throws MalformedURLException { return putData(endpoint, id, input, new Headers(TENANT_HEADER)); } diff --git a/src/test/java/org/folio/services/piece/PieceServiceTest.java b/src/test/java/org/folio/services/piece/PieceServiceTest.java index ad60aab7..00e51c56 100644 --- a/src/test/java/org/folio/services/piece/PieceServiceTest.java +++ b/src/test/java/org/folio/services/piece/PieceServiceTest.java @@ -8,6 +8,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verifyNoInteractions; import java.util.List; import java.util.UUID; @@ -289,4 +291,22 @@ void shouldUpdatePieces(Vertx vertx, VertxTestContext testContext) { }); } + @Test + void shouldNotUpdatePiecesWhenEmpty(Vertx vertx, VertxTestContext testContext) { + new DBClient(vertx, TEST_TENANT).getPgClient().withConn(connection -> { + var conn = spy(connection); + List piecesToUpdate = List.of(); + var updatePiecesFuture = pieceService.updatePieces(piecesToUpdate, conn, TEST_TENANT); + + return testContext.assertComplete(updatePiecesFuture) + .onComplete(ar -> { + List actPieces = ar.result(); + testContext.verify(() -> { + assertThat(actPieces, is(piecesToUpdate)); + verifyNoInteractions(conn); + }); + testContext.completeNow(); + }); + }); + } }