### Question:
TransactionIdTracker { public void awaitUpToDate( long oldestAcceptableTxId, Duration timeout ) throws TransactionFailureException { if ( oldestAcceptableTxId <= BASE_TX_ID ) { return; } if ( !databaseAvailabilityGuard.isAvailable() ) { throw new TransactionFailureException( Status.General.DatabaseUnavailable, "Database unavailable" ); } try { transactionIdStore().awaitClosedTransactionId( oldestAcceptableTxId, timeout.toMillis() ); } catch ( InterruptedException | TimeoutException e ) { if ( e instanceof InterruptedException ) { Thread.currentThread().interrupt(); } throw new TransactionFailureException( Status.Transaction.InstanceStateChanged, e, "Database not up to the requested version: %d. Latest database version is %d", oldestAcceptableTxId, transactionIdStore().getLastClosedTransactionId() ); } } TransactionIdTracker( Supplier<TransactionIdStore> transactionIdStoreSupplier, AvailabilityGuard databaseAvailabilityGuard ); void awaitUpToDate( long oldestAcceptableTxId, Duration timeout ); long newestEncounteredTxId();  }### Answer:
@Test public void shouldReturnImmediatelyForBaseTxIdOrLess() throws Exception { transactionIdTracker.awaitUpToDate( BASE_TX_ID, ofSeconds( 5 ) ); verify( transactionIdStore, never() ).awaitClosedTransactionId( anyLong(), anyLong() ); }
@Test public void shouldWaitForRequestedVersion() throws Exception { long version = 5L; transactionIdTracker.awaitUpToDate( version, DEFAULT_DURATION ); verify( transactionIdStore ).awaitClosedTransactionId( version, DEFAULT_DURATION.toMillis() ); }
@Test public void shouldPropagateTimeoutException() throws Exception { long version = 5L; TimeoutException timeoutException = new TimeoutException(); doThrow( timeoutException ).when( transactionIdStore ).awaitClosedTransactionId( anyLong(), anyLong() ); try { transactionIdTracker.awaitUpToDate( version + 1, ofMillis( 50 ) ); fail( "should have thrown" ); } catch ( TransactionFailureException ex ) { assertEquals( Status.Transaction.InstanceStateChanged, ex.status() ); assertEquals( timeoutException, ex.getCause() ); } }
@Test public void shouldNotWaitIfTheDatabaseIsUnavailable() throws Exception { when( databaseAvailabilityGuard.isAvailable() ).thenReturn( false ); try { transactionIdTracker.awaitUpToDate( 1000, ofMillis( 60_000 ) ); fail( "should have thrown" ); } catch ( TransactionFailureException ex ) { assertEquals( Status.General.DatabaseUnavailable, ex.status() ); } verify( transactionIdStore, never() ).awaitClosedTransactionId( anyLong(), anyLong() ); }