public void testPrimaryOwnerCrash() throws Exception {
    // cache 0 is the originator and backup, cache 1 is the primary owner
    StateSequencer ss = new StateSequencer();
    ss.logicalThread("main", "block_prepare", "crash_primary", "resume_prepare");

    tm(0).begin();
    cache(0).put("k", "v1");
    DummyTransaction tx1 = (DummyTransaction) tm(0).suspend();
    tx1.runPrepare();

    advanceOnInboundRpc(ss, cache(1), matchCommand(PrepareCommand.class).build())
        .before("block_prepare", "resume_prepare");

    Future<DummyTransaction> tx2Future =
        fork(
            () -> {
              tm(0).begin();
              cache(0).put("k", "v2");
              DummyTransaction tx2 = (DummyTransaction) tm(0).suspend();
              tx2.runPrepare();
              return tx2;
            });

    ss.enter("crash_primary");
    killMember(1);
    ss.exit("crash_primary");

    DummyTransaction tx2 = tx2Future.get(10, SECONDS);
    try {
      tx2.runCommit(false);
      fail("tx2 should not be able to commit");
    } catch (Exception e) {
      log.tracef(e, "Received expected exception");
    }

    tx1.runCommit(false);
  }
  protected void doTest(final SplitMode splitMode, boolean txFail, boolean discard)
      throws Exception {
    waitForClusterToForm(OPTIMISTIC_TX_CACHE_NAME);

    final KeyInfo keyInfo = createKeys(OPTIMISTIC_TX_CACHE_NAME);
    final Cache<Object, String> originator = cache(0, OPTIMISTIC_TX_CACHE_NAME);
    final FilterCollection filterCollection =
        createFilters(OPTIMISTIC_TX_CACHE_NAME, discard, getCommandClass(), splitMode);

    Future<Void> put =
        fork(
            () -> {
              final DummyTransactionManager transactionManager =
                  (DummyTransactionManager) originator.getAdvancedCache().getTransactionManager();
              transactionManager.begin();
              keyInfo.putFinalValue(originator);
              final DummyTransaction transaction = transactionManager.getTransaction();
              transaction.runPrepare();
              transaction.runCommit(forceRollback());
              transaction.throwRollbackExceptionIfAny();
              return null;
            });

    filterCollection.await(30, TimeUnit.SECONDS);
    splitMode.split(this);
    filterCollection.unblock();

    try {
      put.get();
      assertFalse(txFail);
    } catch (ExecutionException e) {
      assertTrue(txFail);
    }

    checkLocksDuringPartition(splitMode, keyInfo, discard);

    mergeCluster(OPTIMISTIC_TX_CACHE_NAME);
    finalAsserts(OPTIMISTIC_TX_CACHE_NAME, keyInfo, txFail ? INITIAL_VALUE : FINAL_VALUE);
  }