I am not able to give the entire code and context in one message.
My issue is with the TestContainer behavior
Like I am using the retry like this
public void execute() {
boolean success = false;
int retryCount = 0;
while (!success) {
try {
transactions.run((TransactionAttemptContext ctx) -> {
process(ctx);
});
success = true;
} catch (TransactionFailedException ex) {
Throwable cause = ex.getCause();
if (cause instanceof DocumentExistsException || cause instanceof DuplicateKeyException) {
if (cause.getMessage().contains(getCollectionName(TransactionSubLedgerEntity.class))) {
log.warn("Duplicate event with eventId {} while stock-processing. Event already present",
storeStockMovement.getStockTransaction().stockTransactionId());
success = true;
} else {
retryCount++;
log.warn("Duplicate entry in stockWacSubLedger or stockRefSubLedger eventId {} while stock-processing. Retrying... Attempt {}",
storeStockMovement.getStockTransaction().stockTransactionId(), retryCount);
if (retryCount >= MAX_RETRY_COUNT) {
throw new TransactionProcessingException(
String.format("Exceeded max retries while processing srs event with id %s",
storeStockMovement.getStockTransaction().stockTransactionId()), ex);
}
}
} else if (cause instanceof WacCalculationTransientException) {
throw (WacCalculationTransientException) cause;
} else {
throw new TransactionProcessingException(
String.format("Error while processing stock event with id %s",
storeStockMovement.getStockTransaction().stockTransactionId()), ex);
}
}
}
}
My own logic to retry.
Also, all db operations performed from the process(ctx)
method uses ctx
to maintain the transactional behavior.
For eg:
public TransactionSubLedgerEntity saveEntity(TransactionAttemptContext ctx, TransactionSubLedgerEntity transactionSubLedgerEntity) {
Collection collection = getCollection();
try {
ctx.insert(collection, transactionSubLedgerEntity.getTransactionId(), transactionSubLedgerEntity);
log.info("Inserted new TransactionSubLedgerEntity with ID: {}", transactionSubLedgerEntity.getTransactionId());
} catch (DocumentExistsException e) {
log.error("Duplicate TransactionSubLedgerEntity detected with ID: {}", transactionSubLedgerEntity.getTransactionId());
throw e;
}
return transactionSubLedgerEntity;
}
But my main problem is when I am writing integration tests, where I use couchbase testcontainer
When I try to check the data I saved in my test code, its not coming up. Even though insertion has happened as per the logs in the code inside process(ctx)
method.
Testing code piece
def "Verify that successful stock receipt processing txn"() {
given: "A SRS transfer is present in the system"
buildDepotStockMovement(tpnb, storeId, referenceId, srsTransactionDate)
insertStockWac(tpnb, storeId, 10)
if(rcvEventTpnb!=tpnb)
insertStockWac(rcvEventTpnb,storeId,11)
insertStockRef(referenceId, 10, tpnb, storeId, stockInTransit, createdAt, srsTransactionDate)
//currency mock
ConfigData configData = new ConfigData()
configData.setCurrency("GBP")
CurrencyMapping currencyMapping = new CurrencyMapping()
def storeStockMovement =
createStockReceivingEvent(rcvEventTpnb == null ? tpnb : rcvEventTpnb, storeId, invoiceNo, receiveQty, sourceTransactionDateTime)
currencyMapping.setConfigData(Collections.singletonList(configData))
Mockito.when(configurationService.getCurrencyMappingConfig(STOCK_CURRENCY_COUNTRY_MAPPING,
storeStockMovement.getLocationReferenceEnriched().country()))
.thenReturn(currencyMapping)
Mockito.when(wacService.fetchCurrentWac(Mockito.anyString(), Mockito.any(LocalDate.class), Mockito.anyString()))
.thenReturn(BigDecimal.valueOf(15.25))
Mockito.when(missingPreReqHelper.persistMissingPreReqEvent()).thenReturn(new MissingPreReqEntity())
when: "Stock receipt is received for that referenceId"
String auditId = "test-1"
def command = new StockReceivingProcessingCommand(storeStockMovement, stockProcessorHelper, srsProcessorHelper,
auditId, missingPreReqHelper, transactions)
command.execute()
Thread.sleep(1000)
then: "Expected transaction TransactionCode=#transactionCode ReasonCode=#reasonCode is created"
if (transactionCode >= 0 && reasonCode >= 0) {
QueryCriteria criteria = QueryCriteria.where("storeId").is(storeId)
.and(QueryCriteria.where("tpnb").is(rcvEventTpnb == null ? tpnb : rcvEventTpnb))
.and(QueryCriteria.where("referenceId").is(invoiceNo))
.and(QueryCriteria.where("transactionCode").is(transactionCode))
.and(QueryCriteria.where("reasonCode").is(reasonCode))
def results = couchbaseTemplate.findByQuery(TransactionSubLedgerEntity)
.withConsistency(QueryScanConsistency.REQUEST_PLUS)
.matching(criteria)
.all()
log.info("results {}", results);
log.info("transaction {}", transactionSubLedgerRepository.findAll().toString())
assert results.size() == 1
assert results.stream().findFirst().get().quantity == expectedQty
assert results.stream().findFirst().get().newStockOnHand == expectedSOH
}
}
Here both the logs in results and transactions come as null.