@SuppressWarnings("unchecked")
  @Test
  public void testFailoverAfterProxyFailure() throws InterruptedException {
    Host host = Host.getHost(0);
    VM accessor = host.getVM(0);
    VM datastore = host.getVM(1);
    VM accessor2 = host.getVM(2);
    final boolean cachingProxy = false;

    disconnectAllFromDS(); // some other VMs seem to be hanging around and have the region this
                           // tests uses

    int[] ports = new int[2];
    ports[0] = createRegionsAndStartServerWithTimeout(accessor, true, 5);
    ports[1] = createRegionsAndStartServerWithTimeout(accessor2, true, 5);
    createRegionOnServerWithTimeout(datastore, false, false, 5);

    System.setProperty(GeodeGlossary.GEMFIRE_PREFIX + "bridge.disableShufflingOfEndpoints",
        "true");
    ClientCacheFactory ccf = new ClientCacheFactory();
    setCCF(ports, ccf);
    ClientCache cCache = getClientCache(ccf);
    ClientRegionFactory<CustId, Customer> custrf = cCache.createClientRegionFactory(
        cachingProxy ? ClientRegionShortcut.CACHING_PROXY : ClientRegionShortcut.PROXY);
    ClientRegionFactory<Integer, String> refrf = cCache.createClientRegionFactory(
        cachingProxy ? ClientRegionShortcut.CACHING_PROXY : ClientRegionShortcut.PROXY);
    Region<Integer, String> r = refrf.create(D_REFERENCE);
    Region<CustId, Customer> pr = custrf.create(CUSTOMER);

    TXManagerImpl mgr = getGemfireCache().getTxManager();
    mgr.begin();
    doTxOps(r, pr);

    final DistributedMember myId = cCache.getDistributedSystem().getDistributedMember();
    final DistributedMember accessorId = accessor
        .invoke(ClientServerTransactionDUnitTest::getVMDistributedMember);
    final DistributedMember accessor2Id = accessor2
        .invoke(ClientServerTransactionDUnitTest::getVMDistributedMember);

    SerializableCallable verifyExists =
        new SerializableCallable("verify txstate for client exists") {
          @Override
          public Object call() {
            TXManagerImpl txmgr = getGemfireCache().getTxManager();
            Set<TXId> states = txmgr.getTransactionsForClient((InternalDistributedMember) myId);
            assertEquals(1, states.size()); // only one in-progress transaction
            return null;
          }
        };

    datastore.invoke(verifyExists);

    SerializableCallable getProxyServer = new SerializableCallable("get proxy server") {
      @Override
      public Object call() {
        final TXManagerImpl txmgr = getGemfireCache().getTxManager();
        DistributedMember proxyServer = null;
        TXStateProxyImpl tx = null;
        Set<TXStateProxy> states =
            txmgr.getTransactionStatesForClient((InternalDistributedMember) myId);
        assertEquals(1, states.size());
        Iterator<TXStateProxy> iterator = states.iterator();
        if (iterator.hasNext()) {
          tx = (TXStateProxyImpl) iterator.next();
          assertTrue(tx.isRealDealLocal());
          proxyServer = ((TXState) tx.realDeal).getProxyServer();
        }
        return proxyServer;
      }
    };

    final DistributedMember proxy = (DistributedMember) datastore.invoke(getProxyServer);

    if (proxy.equals(accessorId)) {
      accessor.invoke(JUnit4CacheTestCase::closeCache);
      accessor.invoke(JUnit4DistributedTestCase::disconnectFromDS);
    } else {
      assertTrue(proxy.equals(accessor2Id));
      accessor2.invoke(JUnit4CacheTestCase::closeCache);
      accessor2.invoke(JUnit4DistributedTestCase::disconnectFromDS);
    }

    doTxOps(r, pr);

    SerializableCallable verifyProxyServerChanged =
        new SerializableCallable("verify proxy server is updated") {
          @Override
          public Object call() {
            final TXManagerImpl txmgr = getGemfireCache().getTxManager();
            TXStateProxyImpl tx = null;
            Set<TXStateProxy> states =
                txmgr.getTransactionStatesForClient((InternalDistributedMember) myId);
            assertEquals(1, states.size());
            Iterator<TXStateProxy> iterator = states.iterator();
            if (iterator.hasNext()) {
              tx = (TXStateProxyImpl) iterator.next();
              assertTrue(tx.isRealDealLocal());
            }
            return verifyProxyServerChanged(tx, proxy);
          }
        };
    try {
      datastore.invoke(verifyProxyServerChanged);
    } finally {
      cCache.close();
    }
  }
Tests the basic client-server transaction functionality
geode-core/src/distributedTest/java/org/apache/geode/internal/cache/ClientServerTransactionDUnitTest.java