Skip to content

Commit

Permalink
[MODFISTO-460] Refactored transaction tests, added more
Browse files Browse the repository at this point in the history
  • Loading branch information
damien-git committed Apr 17, 2024
1 parent 530e432 commit b94606b
Show file tree
Hide file tree
Showing 10 changed files with 1,713 additions and 1,344 deletions.
1 change: 0 additions & 1 deletion src/main/java/org/folio/rest/util/ErrorCodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public enum ErrorCodes {
MISSING_FUND_ID("missingFundId", "One of the fields toFundId or fromFundId must be specified"),
ALLOCATION_MUST_BE_POSITIVE("allocationMustBePositive", "Allocation amount must be greater than zero"),
CONFLICT("conflict", "Conflict when updating a record in table {0}: {1}"),
BUDGET_NOT_FOUND_FOR_TRANSACTION("budgetNotFoundForTransaction", "Budget not found for pair fiscalYear-fundId"),
BUDGET_RESTRICTED_EXPENDITURES_ERROR("budgetRestrictedExpendituresError", "Expenditure restriction does not allow this operation"),
BUDGET_RESTRICTED_ENCUMBRANCE_ERROR("budgetRestrictedEncumbranceError", "Encumbrance restriction does not allow this operation"),
PAYMENT_OR_CREDIT_HAS_NEGATIVE_AMOUNT("paymentOrCreditHasNegativeAmount", "A payment or credit has a negative amount");
Expand Down
16 changes: 14 additions & 2 deletions src/test/java/org/folio/StorageTestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
import org.folio.service.rollover.LedgerRolloverServiceTest;
import org.folio.service.rollover.RolloverProgressServiceTest;
import org.folio.service.rollover.RolloverValidationServiceTest;
import org.folio.service.transactions.BatchTransactionServiceTest;
import org.folio.service.transactions.AllocationCreditTest;
import org.folio.service.transactions.EncumbranceTest;
import org.folio.service.transactions.PaymentCreditTest;
import org.folio.service.transactions.PendingPaymentTest;
import org.folio.utils.CalculationUtilsTest;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -203,5 +206,14 @@ class RolloverValidationServiceTestNested extends RolloverValidationServiceTest
class EmailServiceTestNested extends EmailServiceTest {}

@Nested
class BatchTransactionServiceTestNested extends BatchTransactionServiceTest {}
class AllocationCreditTestNested extends AllocationCreditTest {}

@Nested
class EncumbranceTestNested extends EncumbranceTest {}

@Nested
class PaymentCreditTestNested extends PaymentCreditTest {}

@Nested
class PendingPaymentTestNested extends PendingPaymentTest {}
}
17 changes: 0 additions & 17 deletions src/test/java/org/folio/rest/impl/TestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
import static org.junit.Assert.assertThat;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;
Expand Down Expand Up @@ -166,13 +164,6 @@ void deleteDataSuccess(String endpoint, String id) {
.statusCode(204);
}

void deleteDataSuccess(TestEntities testEntity, String id) {
logger.info(String.format("--- %s test: Deleting record with ID %s", testEntity.name(), id));
deleteData(testEntity.getEndpointWithId(), id)
.then().log().ifValidationFails()
.statusCode(204);
}

Response deleteData(String endpoint, String id) {
return deleteData(endpoint, id, TENANT_HEADER);
}
Expand Down Expand Up @@ -249,12 +240,4 @@ void testVerifyEntityDeletion(String endpoint, String id) {
.statusCode(404);
}

protected double subtractValues(double d1, Double ... subtrahends) {
BigDecimal subtrahendSum = Stream.of(subtrahends).map(BigDecimal::valueOf).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
return BigDecimal.valueOf(d1).subtract(subtrahendSum).doubleValue();
}

protected double sumValues(Double ... doubles) {
return Stream.of(doubles).map(BigDecimal::valueOf).reduce(BigDecimal::add).orElse(BigDecimal.ZERO).doubleValue();
}
}
66 changes: 66 additions & 0 deletions src/test/java/org/folio/rest/impl/TransactionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,35 @@
import static org.folio.rest.utils.TenantApiTestUtil.deleteTenant;
import static org.folio.rest.utils.TenantApiTestUtil.purge;
import static org.folio.rest.utils.TenantApiTestUtil.prepareTenant;
import static org.folio.rest.utils.TestEntities.BUDGET;
import static org.folio.rest.utils.TestEntities.FISCAL_YEAR;
import static org.folio.rest.utils.TestEntities.FUND;
import static org.folio.rest.utils.TestEntities.LEDGER;

import io.vertx.core.json.JsonObject;
import org.apache.commons.lang3.tuple.Pair;
import org.folio.rest.jaxrs.model.Batch;
import org.folio.rest.jaxrs.model.Encumbrance;
import org.folio.rest.jaxrs.model.TenantJob;
import org.folio.rest.jaxrs.model.Transaction;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.restassured.http.Header;

import java.util.Collections;
import java.util.UUID;

public class TransactionTest extends TestBase {

protected static final String TRANSACTION_TEST_TENANT = "transactiontesttenant";
protected static final Header TRANSACTION_TENANT_HEADER = new Header(OKAPI_HEADER_TENANT, TRANSACTION_TEST_TENANT);

private static final String BATCH_TRANSACTION_SAMPLE = "data/transactions/batch/batch_with_patch.json";
private static final String BATCH_TRANSACTION_ENDPOINT = "/finance-storage/transactions/batch-all-or-nothing";
private static final String TRANSACTION_ENDPOINT_BY_ID = "/finance-storage/transactions/{id}";
private static TenantJob tenantJob;

@BeforeEach
Expand All @@ -44,4 +57,57 @@ void testBatchTransactionsPatch() {
.statusCode(500);
}

@Test
void testUpdateEncumbranceConflict() {
givenTestData(TRANSACTION_TENANT_HEADER,
Pair.of(FISCAL_YEAR, FISCAL_YEAR.getPathToSampleFile()),
Pair.of(LEDGER, LEDGER.getPathToSampleFile()),
Pair.of(FUND, FUND.getPathToSampleFile()),
Pair.of(BUDGET, BUDGET.getPathToSampleFile()));

String orderId = UUID.randomUUID().toString();
String orderLineId = UUID.randomUUID().toString();

String encumbranceId = UUID.randomUUID().toString();
Transaction encumbrance = new Transaction()
.withId(encumbranceId)
.withCurrency("USD")
.withFromFundId(FUND.getId())
.withTransactionType(Transaction.TransactionType.ENCUMBRANCE)
.withAmount(10.0)
.withFiscalYearId(FISCAL_YEAR.getId())
.withSource(Transaction.Source.PO_LINE)
.withEncumbrance(new Encumbrance()
.withOrderType(Encumbrance.OrderType.ONE_TIME)
.withOrderStatus(Encumbrance.OrderStatus.OPEN)
.withSourcePurchaseOrderId(orderId)
.withSourcePoLineId(orderLineId)
.withInitialAmountEncumbered(10d)
.withSubscription(false)
.withReEncumber(false));

Batch batch1 = new Batch()
.withTransactionsToCreate(Collections.singletonList(encumbrance));
postData(BATCH_TRANSACTION_ENDPOINT, JsonObject.mapFrom(batch1).encodePrettily(), TRANSACTION_TENANT_HEADER)
.then().statusCode(204);

Transaction createdEncumbrance = getDataById(TRANSACTION_ENDPOINT_BY_ID, encumbranceId, TRANSACTION_TENANT_HEADER)
.as(Transaction.class);

Transaction encumbrance2 = JsonObject.mapFrom(createdEncumbrance).mapTo(Transaction.class)
.withAmount(9.0)
.withVersion(1);
Batch batch2 = new Batch()
.withTransactionsToUpdate(Collections.singletonList(encumbrance2));
postData(BATCH_TRANSACTION_ENDPOINT, JsonObject.mapFrom(batch2).encodePrettily(), TRANSACTION_TENANT_HEADER)
.then().statusCode(204);

Transaction encumbrance3 = JsonObject.mapFrom(createdEncumbrance).mapTo(Transaction.class)
.withAmount(8.0);
Batch batch3 = new Batch()
.withTransactionsToUpdate(Collections.singletonList(encumbrance3));
postData(BATCH_TRANSACTION_ENDPOINT, JsonObject.mapFrom(batch3).encodePrettily(), TRANSACTION_TENANT_HEADER)
.then().statusCode(409);
}

}
225 changes: 225 additions & 0 deletions src/test/java/org/folio/service/transactions/AllocationCreditTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
package org.folio.service.transactions;

import io.vertx.junit5.VertxTestContext;
import org.folio.rest.jaxrs.model.Batch;
import org.folio.rest.jaxrs.model.Budget;
import org.folio.rest.jaxrs.model.Transaction;
import org.folio.rest.persist.Criteria.Criterion;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static io.vertx.core.Future.succeededFuture;
import static org.folio.dao.transactions.BatchTransactionDAO.TRANSACTIONS_TABLE;
import static org.folio.rest.impl.BudgetAPI.BUDGET_TABLE;
import static org.folio.rest.jaxrs.model.Transaction.TransactionType.ALLOCATION;
import static org.folio.rest.jaxrs.model.Transaction.TransactionType.TRANSFER;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

public class AllocationCreditTest extends BatchTransactionServiceTestBase {

@Test
void testCreateInitialAllocation(VertxTestContext testContext) {
String transactionId = UUID.randomUUID().toString();
String fundId = UUID.randomUUID().toString();
String fiscalYearId = UUID.randomUUID().toString();

Transaction allocation = new Transaction()
.withId(transactionId)
.withCurrency("USD")
.withToFundId(fundId)
.withTransactionType(ALLOCATION)
.withAmount(5d)
.withFiscalYearId(fiscalYearId);

Batch batch = new Batch();
batch.getTransactionsToCreate().add(allocation);

setupFundBudgetLedger(fundId, fiscalYearId, 0d, 0d, 0d, false, false, false);

Criterion transactionCriterion = createCriterionByIds(List.of(transactionId));
doReturn(succeededFuture(createResults(new ArrayList<Transaction>())))
.when(conn).get(eq(TRANSACTIONS_TABLE), eq(Transaction.class), argThat(
crit -> crit.toString().equals(transactionCriterion.toString())));

doAnswer(invocation -> succeededFuture(createRowSet(invocation.getArgument(1))))
.when(conn).saveBatch(anyString(), anyList());

doAnswer(invocation -> succeededFuture(createRowSet(invocation.getArgument(1))))
.when(conn).updateBatch(anyString(), anyList());

testContext.assertComplete(batchTransactionService.processBatch(batch, requestContext))
.onComplete(event -> {
testContext.verify(() -> {
// Verify allocation creation
ArgumentCaptor<String> saveTableNamesCaptor = ArgumentCaptor.forClass(String.class);
verify(conn, times(1)).saveBatch(saveTableNamesCaptor.capture(), saveEntitiesCaptor.capture());
List<String> saveTableNames = saveTableNamesCaptor.getAllValues();
List<List<Object>> saveEntities = saveEntitiesCaptor.getAllValues();
assertThat(saveTableNames.get(0), equalTo(TRANSACTIONS_TABLE));
Transaction savedTransaction = (Transaction)(saveEntities.get(0).get(0));
assertNotNull(savedTransaction.getMetadata());
assertThat(savedTransaction.getAmount(), equalTo(allocation.getAmount()));

// Verify budget update
ArgumentCaptor<String> updateTableNamesCaptor = ArgumentCaptor.forClass(String.class);
verify(conn, times(1)).updateBatch(updateTableNamesCaptor.capture(), updateEntitiesCaptor.capture());
List<String> updateTableNames = updateTableNamesCaptor.getAllValues();
assertThat(updateTableNames.get(0), equalTo(BUDGET_TABLE));
List<List<Object>> updateEntities = updateEntitiesCaptor.getAllValues();
Budget savedBudget = (Budget)(updateEntities.get(0).get(0));
assertNotNull(savedBudget.getMetadata().getUpdatedDate());
assertThat(savedBudget.getInitialAllocation(), equalTo(10d));
assertThat(savedBudget.getAllocationTo(), equalTo(5d));

});
testContext.completeNow();
});
}

@Test
void testCreateAllocation(VertxTestContext testContext) {
String fundId1 = UUID.randomUUID().toString();
String fundId2 = UUID.randomUUID().toString();
String budgetId1 = UUID.randomUUID().toString();
String budgetId2 = UUID.randomUUID().toString();
String transactionId = UUID.randomUUID().toString();
String fiscalYearId = UUID.randomUUID().toString();

Transaction allocation = new Transaction()
.withId(transactionId)
.withCurrency("USD")
.withFromFundId(fundId1)
.withToFundId(fundId2)
.withTransactionType(ALLOCATION)
.withAmount(5d)
.withFiscalYearId(fiscalYearId);

setup2Funds2Budgets1Ledger(fundId1, fundId2, budgetId1, budgetId2, fiscalYearId);

Batch batch = new Batch();
batch.getTransactionsToCreate().add(allocation);

Criterion transactionCriterion = createCriterionByIds(List.of(transactionId));
doReturn(succeededFuture(createResults(new ArrayList<Transaction>())))
.when(conn).get(eq(TRANSACTIONS_TABLE), eq(Transaction.class), argThat(
crit -> crit.toString().equals(transactionCriterion.toString())));

doAnswer(invocation -> succeededFuture(createRowSet(invocation.getArgument(1))))
.when(conn).saveBatch(anyString(), anyList());

doAnswer(invocation -> succeededFuture(createRowSet(invocation.getArgument(1))))
.when(conn).updateBatch(anyString(), anyList());

testContext.assertComplete(batchTransactionService.processBatch(batch, requestContext))
.onComplete(event -> {
testContext.verify(() -> {
// Verify allocation creation
ArgumentCaptor<String> saveTableNamesCaptor = ArgumentCaptor.forClass(String.class);
verify(conn, times(1)).saveBatch(saveTableNamesCaptor.capture(), saveEntitiesCaptor.capture());
List<String> saveTableNames = saveTableNamesCaptor.getAllValues();
List<List<Object>> saveEntities = saveEntitiesCaptor.getAllValues();
assertThat(saveTableNames.get(0), equalTo(TRANSACTIONS_TABLE));
Transaction savedTransaction = (Transaction)(saveEntities.get(0).get(0));
assertNotNull(savedTransaction.getMetadata());
assertThat(savedTransaction.getAmount(), equalTo(allocation.getAmount()));

// Verify budget updates
ArgumentCaptor<String> updateTableNamesCaptor = ArgumentCaptor.forClass(String.class);
verify(conn, times(1)).updateBatch(updateTableNamesCaptor.capture(), updateEntitiesCaptor.capture());
List<String> updateTableNames = updateTableNamesCaptor.getAllValues();
assertThat(updateTableNames.get(0), equalTo(BUDGET_TABLE));
List<List<Object>> updateEntities = updateEntitiesCaptor.getAllValues();
Budget savedBudget1 = (Budget)(updateEntities.get(0).get(0));
assertThat(savedBudget1.getId(), equalTo(budgetId1));
assertNotNull(savedBudget1.getMetadata().getUpdatedDate());
assertThat(savedBudget1.getAllocationFrom(), equalTo(5d));
Budget savedBudget2 = (Budget)(updateEntities.get(0).get(1));
assertThat(savedBudget2.getId(), equalTo(budgetId2));
assertNotNull(savedBudget2.getMetadata().getUpdatedDate());
assertThat(savedBudget2.getAllocationTo(), equalTo(5d));
});
testContext.completeNow();
});
}

@Test
void testCreateTransfer(VertxTestContext testContext) {
String fundId1 = UUID.randomUUID().toString();
String fundId2 = UUID.randomUUID().toString();
String budgetId1 = UUID.randomUUID().toString();
String budgetId2 = UUID.randomUUID().toString();
String transactionId = UUID.randomUUID().toString();
String fiscalYearId = UUID.randomUUID().toString();

Transaction transfer = new Transaction()
.withId(transactionId)
.withCurrency("USD")
.withFromFundId(fundId1)
.withToFundId(fundId2)
.withTransactionType(TRANSFER)
.withAmount(5d)
.withFiscalYearId(fiscalYearId);

setup2Funds2Budgets1Ledger(fundId1, fundId2, budgetId1, budgetId2, fiscalYearId);

Batch batch = new Batch();
batch.getTransactionsToCreate().add(transfer);

Criterion transactionCriterion = createCriterionByIds(List.of(transactionId));
doReturn(succeededFuture(createResults(new ArrayList<Transaction>())))
.when(conn).get(eq(TRANSACTIONS_TABLE), eq(Transaction.class), argThat(
crit -> crit.toString().equals(transactionCriterion.toString())));

doAnswer(invocation -> succeededFuture(createRowSet(invocation.getArgument(1))))
.when(conn).saveBatch(anyString(), anyList());

doAnswer(invocation -> succeededFuture(createRowSet(invocation.getArgument(1))))
.when(conn).updateBatch(anyString(), anyList());

testContext.assertComplete(batchTransactionService.processBatch(batch, requestContext))
.onComplete(event -> {
testContext.verify(() -> {
// Verify allocation creation
ArgumentCaptor<String> saveTableNamesCaptor = ArgumentCaptor.forClass(String.class);
verify(conn, times(1)).saveBatch(saveTableNamesCaptor.capture(), saveEntitiesCaptor.capture());
List<String> saveTableNames = saveTableNamesCaptor.getAllValues();
List<List<Object>> saveEntities = saveEntitiesCaptor.getAllValues();
assertThat(saveTableNames.get(0), equalTo(TRANSACTIONS_TABLE));
Transaction savedTransaction = (Transaction)(saveEntities.get(0).get(0));
assertNotNull(savedTransaction.getMetadata());
assertThat(savedTransaction.getAmount(), equalTo(transfer.getAmount()));

// Verify budget updates
ArgumentCaptor<String> updateTableNamesCaptor = ArgumentCaptor.forClass(String.class);
verify(conn, times(1)).updateBatch(updateTableNamesCaptor.capture(), updateEntitiesCaptor.capture());
List<String> updateTableNames = updateTableNamesCaptor.getAllValues();
assertThat(updateTableNames.get(0), equalTo(BUDGET_TABLE));
List<List<Object>> updateEntities = updateEntitiesCaptor.getAllValues();
Budget savedBudget1 = (Budget)(updateEntities.get(0).get(0));
assertThat(savedBudget1.getId(), equalTo(budgetId1));
assertNotNull(savedBudget1.getMetadata().getUpdatedDate());
assertThat(savedBudget1.getNetTransfers(), equalTo(-5d));
Budget savedBudget2 = (Budget)(updateEntities.get(0).get(1));
assertThat(savedBudget2.getId(), equalTo(budgetId2));
assertNotNull(savedBudget2.getMetadata().getUpdatedDate());
assertThat(savedBudget2.getNetTransfers(), equalTo(5d));
});
testContext.completeNow();
});
}

}
Loading

0 comments on commit b94606b

Please sign in to comment.