@Test
  public void testTxPutIfAbsent() {
    Host host = Host.getHost(0);
    VM acc = host.getVM(0);
    VM datastore = host.getVM(1);
    initAccessorAndDataStore(acc, datastore, 0);
    VM accessor = getVMForTransactions(acc, datastore);

    final CustId newCustId = new CustId(10);
    final Customer updateCust = new Customer("customer10", "address10");
    final TXId txId = (TXId) accessor.invoke(new SerializableCallable<Object>() {
      @Override
      public Object call() {
        TXManagerImpl mgr = getCache().getTxManager();
        mgr.begin();
        Region<CustId, Customer> cust = getCache().getRegion(CUSTOMER);
        Region<CustId, Customer> rr = getCache().getRegion(D_REFERENCE);
        Customer expectedCust = new Customer("customer" + 1, "address" + 1);
        getCache().getLogger().fine("SWAP:doingPutIfAbsent");
        CustId oldCustId = new CustId(1);
        Customer old = cust.putIfAbsent(oldCustId, updateCust);
        assertThat(expectedCust).as("expected:" + expectedCust + " but was " + old)
            .isEqualTo(old);
        // transaction should be bootstrapped
        old = rr.putIfAbsent(oldCustId, updateCust);
        assertThat(expectedCust).as("expected:" + expectedCust + " but was " + old).isEqualTo(old);
        // now a key that does not exist
        old = cust.putIfAbsent(newCustId, updateCust);
        assertThat(old).isNull();
        old = rr.putIfAbsent(newCustId, updateCust);
        assertThat(old).isNull();
        Region<OrderId, Order> order = getCache().getRegion(ORDER);
        Order oldOrder = order.putIfAbsent(new OrderId(10, newCustId), new Order("order10"));
        assertThat(old).isNull();
        assertThat(oldOrder).isNull();
        assertThat(cust.get(newCustId)).isNotNull();
        assertThat(rr.get(newCustId)).isNotNull();
        TXStateProxy tx = mgr.pauseTransaction();
        assertThat(cust.get(newCustId)).isNull();
        assertThat(rr.get(newCustId)).isNull();
        mgr.unpauseTransaction(tx);
        cust.put(oldCustId, new Customer("foo", "bar"));
        rr.put(oldCustId, new Customer("foo", "bar"));
        return mgr.suspend();
      }
    });

    datastore.invoke(new SerializableCallable<Object>() {
      @Override
      public Object call() {
        Region cust = getCache().getRegion(CUSTOMER);
        int hash1 = PartitionedRegionHelper.getHashKey((PartitionedRegion) cust, new CustId(1));
        int hash10 = PartitionedRegionHelper.getHashKey((PartitionedRegion) cust, new CustId(10));
        TXManagerImpl mgr = getCache().getTxManager();
        assertThat(mgr.isHostedTxInProgress(txId)).isTrue();
        TXStateProxy tx = mgr.getHostedTXState(txId);
        assertThat(tx.getRegions().size()).isEqualTo(3 + (hash1 == hash10 ? 0 : 1));// 2 buckets for
        // the two puts we did in the accessor one dist. region, and one more bucket if Cust1 and
        // Cust10 resolve to different buckets
        for (InternalRegion r : tx.getRegions()) {
          assertThat(r instanceof DistributedRegion).isTrue();
          TXRegionState rs = tx.readRegion(r);
          for (Object key : rs.getEntryKeys()) {
            TXEntryState es = rs.readEntry(key);
            assertThat(es.getValue(key, r, false)).isNotNull();
            assertThat(es.isDirty()).as("key:" + key + " r:" + r.getFullPath()).isTrue();
          }
        }
        return null;
      }
    });
    accessor.invoke(new SerializableCallable<Object>() {
      @Override
      public Object call() {
        TXManagerImpl mgr = getCache().getTxManager();
        mgr.resume(txId);
        mgr.commit();
        Region<CustId, Customer> cust = getCache().getRegion(CUSTOMER);
        Region<CustId, Customer> rr = getCache().getRegion(D_REFERENCE);
        assertThat(updateCust).isEqualTo(cust.get(newCustId));
        assertThat(updateCust).isEqualTo(rr.get(newCustId));
        // test conflict
        mgr.begin();
        CustId conflictCust = new CustId(11);
        cust.putIfAbsent(conflictCust, new Customer("name11", "address11"));
        TXStateProxy tx = mgr.pauseTransaction();
        cust.put(conflictCust, new Customer("foo", "bar"));
        mgr.unpauseTransaction(tx);
        assertThatThrownBy(mgr::commit).isInstanceOf(CommitConflictException.class);
        return null;
      }
    });

  }
Make sure that getEntry returns null properly and values when it should
geode-core/src/distributedTest/java/org/apache/geode/internal/cache/RemoteTransactionDUnitTest.java