private void doTestListeners(final OP op) {
    Host host = Host.getHost(0);
    VM acc = host.getVM(0);
    VM datastore = host.getVM(1);
    initAccessorAndDataStore(acc, datastore, 0);
    VM accessor = getVMForTransactions(acc, datastore);

    accessor.invoke(new SerializableCallable<Object>() {
      @Override
      public Object call() {
        Region ref = getCache().getRegion(D_REFERENCE);
        ref.getAttributesMutator().addCacheListener(new TestCacheListener(true));
        ref.getAttributesMutator().setCacheWriter(new TestCacheWriter(true));
        Region cust = getCache().getRegion(CUSTOMER);
        cust.getAttributesMutator().addCacheListener(new TestCacheListener(true));
        cust.getAttributesMutator().setCacheWriter(new TestCacheWriter(true));
        Region order = getCache().getRegion(ORDER);
        order.getAttributesMutator().addCacheListener(new TestCacheListener(true));
        order.getAttributesMutator().setCacheWriter(new TestCacheWriter(true));
        getCache().getTxManager().addListener(new TestTxListener(true));
        if (!getCache().isClient()) {
          getCache().getTxManager().setWriter(new TestTxWriter(true));
        }
        return null;
      }
    });

    SerializableCallable<Object> addListenersToDataStore = new SerializableCallable<Object>() {
      @Override
      public Object call() {
        Region ref = getCache().getRegion(D_REFERENCE);
        ref.getAttributesMutator().addCacheListener(new TestCacheListener(false));
        ref.getAttributesMutator().setCacheWriter(new TestCacheWriter(false));
        Region cust = getCache().getRegion(CUSTOMER);
        cust.getAttributesMutator().addCacheListener(new TestCacheListener(false));
        cust.getAttributesMutator().setCacheWriter(new TestCacheWriter(false));
        Region order = getCache().getRegion(ORDER);
        order.getAttributesMutator().addCacheListener(new TestCacheListener(false));
        order.getAttributesMutator().setCacheWriter(new TestCacheWriter(false));
        getCache().getTxManager().addListener(new TestTxListener(false));
        if (!getCache().isClient()) {
          getCache().getTxManager().setWriter(new TestTxWriter(false));
        }
        return null;
      }
    };
    datastore.invoke(addListenersToDataStore);

    TXId txId = (TXId) accessor.invoke(new DoOpsInTX(op));

    // Invalidate operations don't fire cache writers, so don't assert they were fired.
    if (op != OP.INVALIDATE) {
      // Ensure the cache writer was not fired in accessor
      accessor.invoke(new SerializableCallable<Object>() {
        @Override
        public Object call() {
          Region cust = getCache().getRegion(CUSTOMER);
          assertThat(((TestCacheWriter) cust.getAttributes().getCacheWriter()).wasFired).isFalse();
          Region order = getCache().getRegion(ORDER);
          assertThat(((TestCacheWriter) order.getAttributes().getCacheWriter()).wasFired).isFalse();
          Region ref = getCache().getRegion(D_REFERENCE);
          assertThat(((TestCacheWriter) ref.getAttributes().getCacheWriter()).wasFired).isFalse();
          return null;
        }
      });

      // Ensure the cache writer was fired in the primary
      datastore.invoke(new SerializableCallable<Object>() {
        @Override
        public Object call() {
          Region cust = getCache().getRegion(CUSTOMER);
          assertThat(((TestCacheWriter) cust.getAttributes().getCacheWriter()).wasFired).isTrue();
          Region order = getCache().getRegion(ORDER);
          assertThat(((TestCacheWriter) order.getAttributes().getCacheWriter()).wasFired).isTrue();
          Region ref = getCache().getRegion(D_REFERENCE);
          assertThat(((TestCacheWriter) ref.getAttributes().getCacheWriter()).wasFired).isTrue();
          return null;
        }
      });
    }

    accessor.invoke(new SerializableCallable<Object>() {
      @Override
      public Object call() {
        CacheTransactionManager mgr = getCache().getTxManager();
        mgr.resume(txId);
        mgr.commit();
        return null;
      }
    });

    datastore.invoke(new SerializableCallable<Object>() {
      @Override
      public Object call() {
        TestTxListener l = (TestTxListener) getCache().getTxManager().getListener();
        assertThat(l.isListenerInvoked()).isTrue();
        return null;
      }
    });
    SerializableCallable<Object> verifyListeners = new SerializableCallable<Object>() {
      @Override
      public Object call() throws Exception {
        Region cust = getCache().getRegion(CUSTOMER);
        Region order = getCache().getRegion(ORDER);
        throwListenerException(cust);
        throwListenerException(order);
        throwWriterException(cust);
        throwWriterException(order);
        if (!getCache().isClient()) {
          throwTransactionCallbackException();
        }
        return null;
      }

      private void throwTransactionCallbackException() throws Exception {
        TestTxListener l = (TestTxListener) getCache().getTxManager().getListener();
        if (l.ex != null) {
          throw l.ex;
        }
        TestTxWriter w = (TestTxWriter) getCache().getTxManager().getWriter();
        if (w.ex != null) {
          throw w.ex;
        }
      }

      private void throwListenerException(Region r) throws Exception {
        Exception e = null;
        CacheListener listener = r.getAttributes().getCacheListeners()[0];
        if (listener instanceof TestCacheListener) {
          e = ((TestCacheListener) listener).ex;
        } else {
          // e = ((ClientListener)listener).???
        }
        if (e != null) {
          throw e;
        }
      }

      private void throwWriterException(Region r) throws Exception {
        Exception e = null;
        CacheListener listener = r.getAttributes().getCacheListeners()[0];
        if (listener instanceof TestCacheListener) {
          e = ((TestCacheListener) listener).ex;
        } else {
          // e = ((ClientListener)listener).???
        }
        if (e != null) {
          throw e;
        }
      }
    };
    accessor.invoke(verifyListeners);
    datastore.invoke(verifyListeners);
  }
When we have narrowed down on a target node for a transaction, test that we throw an exception
if that node does not host primary for subsequent entries
geode-core/src/distributedTest/java/org/apache/geode/internal/cache/RemoteTransactionDUnitTest.java