My issue is with the TestContainer behavior. I am trying to test my code in couchbase testcontainer but facing certain anomaly.
My main part of code
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);
}
}
}
}
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.
-
Would you add the Couchbase Server version and the Couchbase Java SDK version that you're using, please?Matthew Groves– Matthew Groves2025年02月28日 17:58:26 +00:00Commented Feb 28, 2025 at 17:58
1 Answer 1
I answered this on your post to forums couchbase com. Since stackoverflow will spank me if I post the link, here's my post copy/pasted from there
ctx.insert(collection,
I don’t think your issue is transaction related.
Avoid mixing-and-matching the Couchbase Java SDK with Spring Data Couchbase. Spring Data Couchbase expects every document to have a _class property, and uses that as a predicate for all operations that are not -ById. So where you’ve used the Java SDK to insert a TransactionSubLedgerEntity document, it does not have a _class property. So when spring data queries with "SELECT ... FROM ... WHERE ... AND _class = "com.example.TransactionSubLedgerEntity" it will only find documents inserted by Spring Data Couchbase (which have the _class property).
If you attempt to retrieve the document that you inserted using findById() - I believe you will find it.
There are exceptions, but by and large - that’s the deal.
Comments
Explore related questions
See similar questions with these tags.