1

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.

Matthew Groves
26.2k11 gold badges76 silver badges126 bronze badges
asked Feb 28, 2025 at 1:16
1
  • Would you add the Couchbase Server version and the Couchbase Java SDK version that you're using, please? Commented Feb 28, 2025 at 17:58

1 Answer 1

0

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.

answered Mar 21, 2025 at 17:48
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.