Skip to content

Commit

Permalink
Simplify Waiter
Browse files Browse the repository at this point in the history
  • Loading branch information
shreyax committed Sep 5, 2024
1 parent 3f857a1 commit 1990c34
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 64 deletions.
34 changes: 17 additions & 17 deletions src/test-support/java/com/lmax/solana4j/SolanaNodeDsl.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void airdrop(final String... args)
final long recentBlockHeight = solanaDriver.getBlockHeight();
waitForBlockHeight(recentBlockHeight + 1);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void retrieveAddressLookupTable(final String... args)
Expand All @@ -92,7 +92,7 @@ public void retrieveAddressLookupTable(final String... args)

final TestPublicKey account = testContext.data(TestDataType.TEST_PUBLIC_KEY).lookup(params.value("lookupTableAddress"));

final AccountInfo accountInfo = new Waiter().waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getAccountInfo(account)));
final AccountInfo accountInfo = Waiter.waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getAccountInfo(account)));

final List<PublicKey> expectedAddresses = stream(params.values("addresses"))
.map(address -> testContext.data(TestDataType.TEST_KEY_PAIR).lookup(address).getSolana4jPublicKey())
Expand Down Expand Up @@ -123,7 +123,7 @@ public void createAddressLookupTable(final String... args)
// intermittency caused by slot not moving on to the next slot before including in the sent transaction
waitForSlot(recentSlot + 1);
final String transactionSignature = solanaDriver.createAddressLookupTable(programDerivedAddress, authority, payer, SolanaEncoding.slot(recentSlot));
new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void extendAddressLookupTable(final String... args)
Expand Down Expand Up @@ -153,7 +153,7 @@ public void extendAddressLookupTable(final String... args)

final String transactionSignature = solanaDriver.extendAddressLookupTable(addressLookupTable, authority, payer, addresses, addressLookupTables);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void waitForSlot(final String... args)
Expand All @@ -163,7 +163,7 @@ public void waitForSlot(final String... args)
new RequiredArg("slot")
);

new Waiter().waitFor(new IsEqualToAssertion<>(true, () -> solanaDriver.getSlot() > params.valueAsLong("slot")));
Waiter.waitFor(new IsEqualToAssertion<>(true, () -> solanaDriver.getSlot() > params.valueAsLong("slot")));
}

public void createMintAccount(final String... args)
Expand Down Expand Up @@ -195,7 +195,7 @@ public void createMintAccount(final String... args)
final long recentBlockHeight = solanaDriver.getBlockHeight();
waitForBlockHeight(recentBlockHeight + 1);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void mintTo(final String... args)
Expand Down Expand Up @@ -224,7 +224,7 @@ public void mintTo(final String... args)

final String transactionSignature = solanaDriver.mintTo(tokenProgram.getFactory(), tokenMint, to, amount, authority, payer, addressLookupTables);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void createTokenAccount(final String... args)
Expand Down Expand Up @@ -258,7 +258,7 @@ public void createTokenAccount(final String... args)
ACCOUNT_LAYOUT_SPAN,
addressLookupTables);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void tokenBalance(final String... args)
Expand All @@ -271,7 +271,7 @@ public void tokenBalance(final String... args)
final TestPublicKey address = testContext.data(TestDataType.TEST_PUBLIC_KEY).lookup(params.value("address"));
final String amount = params.value("amount");

new Waiter().waitFor(new IsEqualToAssertion<>(amount, () -> solanaDriver.getTokenBalance(address.getPublicKeyBase58())));
Waiter.waitFor(new IsEqualToAssertion<>(amount, () -> solanaDriver.getTokenBalance(address.getPublicKeyBase58())));
}

public void balance(final String... args)
Expand All @@ -284,7 +284,7 @@ public void balance(final String... args)
final TestPublicKey address = testContext.data(TestDataType.TEST_PUBLIC_KEY).lookup(params.value("address"));
final Sol sol = new Sol(params.valueAsBigDecimal("amountSol"));

new Waiter().waitFor(new IsEqualToAssertion<>(sol.lamports(), () -> solanaDriver.getBalance(address.getPublicKeyBase58())));
Waiter.waitFor(new IsEqualToAssertion<>(sol.lamports(), () -> solanaDriver.getBalance(address.getPublicKeyBase58())));
}

public void tokenTransfer(final String... args)
Expand Down Expand Up @@ -313,7 +313,7 @@ public void tokenTransfer(final String... args)

final String transactionSignature = solanaDriver.tokenTransfer(tokenProgram, from, to, owner, amount, payer, addressLookupTables);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void createNonceAccount(final String... args)
Expand All @@ -336,7 +336,7 @@ public void createNonceAccount(final String... args)

final String transactionSignature = solanaDriver.createNonceAccount(account, authority, payer, NONCE_ACCOUNT_LENGTH, addressLookupTables);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

public void advanceNonce(final String... args)
Expand All @@ -361,7 +361,7 @@ public void advanceNonce(final String... args)

final String transactionSignature = solanaDriver.advanceNonce(account, authority, payer, addressLookupTables);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));

if (nonce.isPresent())
{
Expand Down Expand Up @@ -410,7 +410,7 @@ public void transfer(final String... args)

final String transactionSignature = solanaDriver.transfer(from, to, sol.lamports(), payer, addressLookupTables);

new Waiter().waitFor(transactionFinalized(transactionSignature));
Waiter.waitFor(transactionFinalized(transactionSignature));
}

private IsNotNullAssertion<TransactionData> transactionFinalized(final String transactionSignature)
Expand Down Expand Up @@ -456,7 +456,7 @@ public void createAssociatedTokenAddress(final String... args)
addressLookupTables
);

new Waiter().waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getTransactionResponse(transactionSignature).getTransaction()));
Waiter.waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getTransactionResponse(transactionSignature).getTransaction()));
}

public void maybeCreateAndExtendAddressLookupTable(final String... args)
Expand All @@ -483,11 +483,11 @@ public void maybeCreateAndExtendAddressLookupTable(final String... args)

private void waitForSlot(final long slot)
{
new Waiter().waitFor(new IsEqualToAssertion<>(true, () -> solanaDriver.getSlot() > slot));
Waiter.waitFor(new IsEqualToAssertion<>(true, () -> solanaDriver.getSlot() > slot));
}

private void waitForBlockHeight(final long blockHeight)
{
new Waiter().waitFor(new IsEqualToAssertion<>(true, () -> solanaDriver.getBlockHeight() > blockHeight));
Waiter.waitFor(new IsEqualToAssertion<>(true, () -> solanaDriver.getBlockHeight() > blockHeight));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ public void doAssert()
try
{
final T actual = actualSupplier.get();
LOGGER.info("Expected value {} and actual value {}.", expected, actual);
LOGGER.debug("Expected value {} and actual value {}.", expected, actual);
assertThat(expected).isEqualTo(actual);
}
catch (final Exception e)
{
LOGGER.info("Something went wrong trying to get the actual value: {}", e.getMessage());
LOGGER.debug("Something went wrong trying to get the actual value: {}", e.getMessage());
throw e;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public void doAssert()
try
{
final T actual = actualSupplier.get();
LOGGER.info("Actual value {}.", actual);
LOGGER.debug("Actual value {}.", actual);
assertThat(actual).isNotNull();
}
catch (final Exception e)
{
LOGGER.info("Something went wrong trying to get the actual value: {}", e.getMessage());
LOGGER.debug("Something went wrong trying to get the actual value: {}", e.getMessage());
throw e;
}
}
Expand Down
85 changes: 42 additions & 43 deletions src/test-support/java/com/lmax/solana4j/assertion/Waiter.java
Original file line number Diff line number Diff line change
@@ -1,70 +1,69 @@
package com.lmax.solana4j.assertion;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

public class Waiter
public final class Waiter
{
private static final Logger LOGGER = LoggerFactory.getLogger(Waiter.class);
private static final Random RANDOM = new Random();
private static final Duration DEFAULT_INITIAL_DELAY = Duration.ZERO;
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(30);
private static final Duration DEFAULT_POLLING_INTERVAL = Duration.ofSeconds(3);

private int retries = 10;
private Duration maximumBackoff = Duration.ofSeconds(3);
private Duration initialDelay = Duration.ofSeconds(0);
private final Duration initialDelay;
private final Duration timeout;
private final Duration pollingInterval;

public <T> T waitFor(final Assertion<T> assertion)
private Waiter()
{
LockSupport.parkNanos(this.initialDelay.toNanos());
this(DEFAULT_INITIAL_DELAY, DEFAULT_TIMEOUT, DEFAULT_POLLING_INTERVAL);
}

for (int i = 0; i < retries; i++)
{
try
{
assertion.doAssert();
return assertion.getActual();
}
catch (final Throwable throwable)
{
final long exponentialBackoff = calculateExponentialBackoffDelay(i + 1);
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(exponentialBackoff));
}
}
throw new AssertionError("Waiting for condition that never happened. " + ZonedDateTime.now());
private Waiter(final Duration initialDelay, final Duration timeout, final Duration pollingInterval)
{
this.initialDelay = initialDelay;
this.timeout = timeout;
this.pollingInterval = pollingInterval;
}

public Waiter withRetries(final int retries)
public Waiter withInitialDelay(final Duration initialDelay)
{
this.retries = retries;
return this;
return new Waiter(initialDelay, timeout, pollingInterval);
}

public Waiter withMaximumBackoff(final Duration maximumBackOff)
public Waiter withTimeout(final Duration timeout)
{
this.maximumBackoff = maximumBackOff;
return this;
return new Waiter(initialDelay, timeout, pollingInterval);
}

public Waiter withInitialDelay(final Duration initialDelay)
public Waiter withPollingInterval(final Duration pollingInterval)
{
this.initialDelay = initialDelay;
return this;
return new Waiter(initialDelay, timeout, pollingInterval);
}

private long calculateExponentialBackoffDelay(final int attempt)
public <T> T waitForAssertion(final Assertion<T> assertion)
{
long delay = (1L << (attempt - 1));
delay = Math.min(delay, maximumBackoff.toSeconds());
if (delay > 1)
final long endTimeMillis = System.currentTimeMillis() + timeout.toMillis();

LockSupport.parkNanos(initialDelay.toNanos());
while (System.currentTimeMillis() < endTimeMillis)
{
delay = delay / 2 + RANDOM.nextInt((int) delay / 2);
try
{
assertion.doAssert();
return assertion.getActual();
}
catch (final Throwable throwable)
{
LockSupport.parkNanos(pollingInterval.toNanos());
}
}
LOGGER.debug("Backing off, delay now is {} seconds.", delay);
return delay;

throw new AssertionError("Waiting for condition that never happened. " + ZonedDateTime.now());
}

public static <T> T waitFor(final Assertion<T> assertion)
{
return new Waiter().waitForAssertion(assertion);
}
}

0 comments on commit 1990c34

Please sign in to comment.