@Test
  public void whenReadLockAcquiredByOther_thenIncrementSucceedsButCommitFails() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn otherTx = transactionFactory.newTxn();
    ref.getLock().acquire(otherTx, LockMode.Read);

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);

    ref.increment(5);

    try {
      tx.commit();
      fail();
    } catch (ReadWriteConflict expected) {
    }

    assertIsAborted(tx);
    assertVersionAndValue(ref, initialVersion, initialValue);
    assertRefHasReadLock(ref, otherTx);
    assertReadLockCount(ref, 1);
  }
  @Test
  public void whenNoTransaction_thenTxnMandatoryException() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    try {
      ref.increment(5);
      fail();
    } catch (TxnMandatoryException expected) {
    }

    assertVersionAndValue(ref, initialVersion, initialValue);
  }
  @Test
  public void whenSuccess() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);

    ref.increment(5);

    tx.commit();

    assertIsCommitted(tx);
    assertVersionAndValue(ref, initialVersion + 1, initialValue + 5);
  }
  @Test
  public void whenPreparedTransactionFound_thenPreparedTxnException() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);
    tx.prepare();

    try {
      ref.increment(5);
      fail();
    } catch (PreparedTxnException expected) {
    }

    assertIsAborted(tx);
    assertVersionAndValue(ref, initialVersion, initialValue);
  }
  @Test
  public void whenListenersAvailable() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    long amount = 4;
    TxnLongAwaitThread thread = new TxnLongAwaitThread(ref, initialValue + amount);
    thread.start();

    sleepMs(500);

    GammaTxn tx = transactionFactory.newTxn();
    setThreadLocalTxn(tx);
    ref.increment(amount);
    tx.commit();

    joinAll(thread);

    assertVersionAndValue(ref, initialVersion + 1, initialValue + amount);
  }
  @Test
  public void whenReadonlyTransaction_thenReadonlyException() {
    long initialValue = 10;
    GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
    long initialVersion = ref.getVersion();

    GammaTxn tx =
        stm.newTxnFactoryBuilder()
            .setReadonly(true)
            .setSpeculative(false)
            .newTransactionFactory()
            .newTxn();
    setThreadLocalTxn(tx);

    try {
      ref.increment(5);
      fail();
    } catch (ReadonlyException expected) {
    }

    assertIsAborted(tx);
    assertVersionAndValue(ref, initialVersion, initialValue);
  }