A Java DSL for synchronizing asynchronous operations
—
Global defaults, fail-fast conditions, custom executors, and logging for complex testing scenarios and performance optimization.
Set default behavior for all Awaitility await statements.
/**
* Set default timeout for all await statements
* @param defaultTimeout maximum wait time for conditions
*/
static void setDefaultTimeout(Duration defaultTimeout);
/**
* Set default timeout using value and time unit
* @param timeout timeout value
* @param unit time unit for timeout
*/
static void setDefaultTimeout(long timeout, TimeUnit unit);/**
* Set default poll interval for all await statements
* @param pollInterval time between condition evaluations
*/
static void setDefaultPollInterval(Duration pollInterval);
/**
* Set default poll interval using value and time unit
* @param pollInterval interval value
* @param unit time unit for interval
*/
static void setDefaultPollInterval(long pollInterval, TimeUnit unit);
/**
* Set default poll interval using custom strategy
* @param pollInterval polling strategy implementation
*/
static void setDefaultPollInterval(PollInterval pollInterval);
/**
* Set default poll delay for all await statements
* @param pollDelay initial delay before first condition check
*/
static void setDefaultPollDelay(Duration pollDelay);
/**
* Set default poll delay using value and time unit
* @param pollDelay delay value
* @param unit time unit for delay
*/
static void setDefaultPollDelay(long pollDelay, TimeUnit unit);/**
* Reset all configuration to default values:
* - timeout: 10 seconds
* - poll interval: 100 milliseconds
* - poll delay: 100 milliseconds
* - catch uncaught exceptions: true
* - ignore exceptions: false
* - no condition evaluation listener
* - no fail fast condition
*/
static void reset();Global Configuration Examples:
// Configure defaults in test setup
@BeforeClass
public static void setupAwaitility() {
setDefaultTimeout(Duration.ofMinutes(2));
setDefaultPollInterval(Duration.ofMillis(50));
setDefaultPollDelay(Duration.ofMillis(10));
}
@AfterClass
public static void cleanupAwaitility() {
reset(); // Clean slate for other tests
}
// Configure for specific test environments
public static void configureForIntegrationTests() {
setDefaultTimeout(5, MINUTES); // Longer timeouts
setDefaultPollInterval(500, MILLISECONDS); // Less frequent polling
setDefaultPollDelay(1, SECONDS); // Initial delay
}
public static void configureForUnitTests() {
setDefaultTimeout(10, SECONDS); // Shorter timeouts
setDefaultPollInterval(10, MILLISECONDS); // Frequent polling
setDefaultPollDelay(0, MILLISECONDS); // No initial delay
}Configure terminal failure conditions to avoid unnecessary waiting.
/**
* Set default fail-fast condition for all await statements
* If condition ever returns true, terminate with TerminalFailureException
* @param defaultFailFastCondition callable that indicates terminal failure
*/
static void setDefaultFailFastCondition(Callable<Boolean> defaultFailFastCondition);
/**
* Set default fail-fast condition with descriptive reason
* @param failFastFailureReason description included in exception
* @param defaultFailFastCondition callable that indicates terminal failure
*/
static void setDefaultFailFastCondition(String failFastFailureReason,
Callable<Boolean> defaultFailFastCondition);/**
* Set default fail-fast assertion for all await statements
* If assertion throws exception, terminate with TerminalFailureException
* @param defaultFailFastAssertion runnable that performs failure checks
*/
static void setDefaultFailFastCondition(ThrowingRunnable defaultFailFastAssertion);
/**
* Set default fail-fast assertion with descriptive reason
* @param failFastFailureReason description included in exception
* @param defaultFailFastAssertion runnable that performs failure checks
*/
static void setDefaultFailFastCondition(String failFastFailureReason,
ThrowingRunnable defaultFailFastAssertion);/**
* Set fail-fast condition for this await statement
* @param failFastCondition callable that indicates terminal failure
* @return ConditionFactory for further configuration
*/
ConditionFactory failFast(Callable<Boolean> failFastCondition);
/**
* Set fail-fast condition with reason for this await statement
* @param failFastFailureReason description for failure
* @param failFastCondition callable that indicates terminal failure
* @return ConditionFactory for further configuration
*/
ConditionFactory failFast(String failFastFailureReason,
Callable<Boolean> failFastCondition);
/**
* Set fail-fast assertion for this await statement
* @param failFastAssertion runnable that performs failure checks
* @return ConditionFactory for further configuration
*/
ConditionFactory failFast(ThrowingRunnable failFastAssertion);
/**
* Set fail-fast assertion with reason for this await statement
* @param failFastFailureReason description for failure
* @param failFastAssertion runnable that performs failure checks
* @return ConditionFactory for further configuration
*/
ConditionFactory failFast(String failFastFailureReason,
ThrowingRunnable failFastAssertion);Fail-Fast Examples:
// Global fail-fast for system shutdown
setDefaultFailFastCondition("System is shutting down",
() -> systemStatus.equals("SHUTDOWN"));
// Per-await fail-fast for error conditions
await().failFast("Database connection lost",
() -> !databaseConnection.isValid(1))
.until(() -> dataProcessor.isComplete());
// Assertion-based fail-fast
await().failFast("Critical error occurred", () -> {
assertThat(errorCount.get()).isLessThan(10);
assertThat(systemHealth.getStatus()).isNotEqualTo(Status.CRITICAL);
})
.until(() -> operationCompletes());
// Complex fail-fast conditions
await().failFast("Service degradation detected", () -> {
double errorRate = errorCount.get() / (double) requestCount.get();
return errorRate > 0.1 || // More than 10% error rate
responseTime.get() > 5000 || // Response time > 5s
memoryUsage.get() > 0.9; // Memory usage > 90%
})
.until(() -> healthCheck.isHealthy());Configure custom execution strategies for condition evaluation.
/**
* Set default executor service for all await statements
* @param executorService custom executor for condition evaluation
*/
static void pollExecutorService(ExecutorService executorService);
/**
* Set executor service for this await statement
* @param executorService custom executor for condition evaluation
* @return ConditionFactory for further configuration
*/
ConditionFactory pollExecutorService(ExecutorService executorService);/**
* Set default thread supplier for all await statements
* @param threadSupplier function that creates threads for polling
*/
static void pollThread(Function<Runnable, Thread> threadSupplier);
/**
* Set thread supplier for this await statement
* @param threadSupplier function that creates threads for polling
* @return ConditionFactory for further configuration
*/
ConditionFactory pollThread(Function<Runnable, Thread> threadSupplier);/**
* Configure all await statements to poll in same thread as test
* Use with test framework timeouts for safety
*/
static void pollInSameThread();
/**
* Configure this await statement to poll in same thread as test
* @return ConditionFactory for further configuration
*/
ConditionFactory pollInSameThread();Thread Management Examples:
// Custom executor with specific thread pool size
ExecutorService customExecutor = Executors.newFixedThreadPool(2, r -> {
Thread t = new Thread(r);
t.setName("Awaitility-Custom-" + t.getId());
t.setDaemon(true);
return t;
});
// Set as default
pollExecutorService(customExecutor);
// Or use for specific await
await().pollExecutorService(customExecutor)
.until(() -> expensiveOperation.isComplete());
// Custom thread with priority
await().pollThread(runnable -> {
Thread thread = new Thread(runnable);
thread.setName("HighPriorityAwait");
thread.setPriority(Thread.MAX_PRIORITY);
thread.setDaemon(true);
return thread;
})
.until(() -> criticalOperation.isComplete());
// Same thread execution with JUnit timeout
@Test(timeout = 10000) // 10 second timeout
public void testWithSameThread() {
await().pollInSameThread()
.until(() -> quickOperation.isComplete());
}Configure detailed logging and monitoring of condition evaluation.
/**
* Set default condition evaluation listener for all await statements
* @param defaultConditionEvaluationListener listener for evaluation events
*/
static void setDefaultConditionEvaluationListener(
ConditionEvaluationListener defaultConditionEvaluationListener);
/**
* Set condition evaluation listener for this await statement
* @param conditionEvaluationListener listener for evaluation events
* @return ConditionFactory for further configuration
*/
ConditionFactory conditionEvaluationListener(
ConditionEvaluationListener conditionEvaluationListener);/**
* Enable default logging to System.out for all await statements
*/
static void setDefaultLogging();
/**
* Enable custom logging for all await statements
* @param logPrinter consumer that handles log messages
*/
static void setLogging(Consumer<String> logPrinter);
/**
* Set custom logging listener for all await statements
* @param loggingListener listener that handles evaluation logging
*/
static void setLoggingListener(ConditionEvaluationListener loggingListener);
/**
* Enable default logging for this await statement
* @return ConditionFactory for further configuration
*/
ConditionFactory logging();
/**
* Enable custom logging for this await statement
* @param logPrinter consumer that handles log messages
* @return ConditionFactory for further configuration
*/
ConditionFactory logging(Consumer<String> logPrinter);Logging Examples:
// Enable default logging globally
setDefaultLogging();
// Custom logging to file
Logger logger = LoggerFactory.getLogger("AwaitilityTest");
setLogging(message -> logger.debug("Awaitility: {}", message));
// Custom evaluation listener
setDefaultConditionEvaluationListener(new ConditionEvaluationListener<Object>() {
@Override
public void conditionEvaluated(EvaluatedCondition<Object> condition) {
System.out.printf("Evaluation %d: %s = %s%n",
condition.getElapsedTimeInMS(),
condition.getDescription(),
condition.getValue());
}
@Override
public void beforeEvaluation(StartEvaluationEvent<Object> startEvaluationEvent) {
System.out.println("Starting evaluation of: " +
startEvaluationEvent.getDescription());
}
@Override
public void onTimeout(TimeoutEvent timeoutEvent) {
System.err.println("Timeout after: " + timeoutEvent.getElapsedTimeInMS() + "ms");
}
});
// Per-await custom logging
await().logging(msg -> System.out.println("Custom: " + msg))
.until(() -> operation.isComplete());
// Structured logging with additional context
await().conditionEvaluationListener(new ConditionEvaluationListener<Boolean>() {
@Override
public void conditionEvaluated(EvaluatedCondition<Boolean> condition) {
Map<String, Object> logData = Map.of(
"elapsed_ms", condition.getElapsedTimeInMS(),
"value", condition.getValue(),
"remaining_time_ms", condition.getRemainingTimeInMS(),
"description", condition.getDescription()
);
logger.info("Condition evaluation: {}", logData);
}
}).until(() -> complexOperation.isComplete());Complex configuration scenarios combining multiple advanced features.
public class AwaitilityConfig {
public static void configureForEnvironment(String environment) {
reset(); // Start clean
switch (environment.toLowerCase()) {
case "development":
configureDevelopment();
break;
case "integration":
configureIntegration();
break;
case "production":
configureProduction();
break;
default:
configureDefault();
}
}
private static void configureDevelopment() {
setDefaultTimeout(30, SECONDS);
setDefaultPollInterval(100, MILLISECONDS);
setDefaultLogging(); // Enable logging for debugging
// Fail fast on obvious errors
setDefaultFailFastCondition("Service crashed",
() -> serviceStatus.equals("CRASHED"));
}
private static void configureIntegration() {
setDefaultTimeout(5, MINUTES);
setDefaultPollInterval(500, MILLISECONDS);
setDefaultPollDelay(1, SECONDS);
// Custom executor for integration tests
ExecutorService integrationExecutor =
Executors.newFixedThreadPool(4);
pollExecutorService(integrationExecutor);
// Comprehensive fail-fast conditions
setDefaultFailFastCondition("Integration environment failure", () -> {
return !databaseHealthy() ||
!messageQueueHealthy() ||
!externalServiceHealthy();
});
}
private static void configureProduction() {
setDefaultTimeout(10, MINUTES);
setDefaultPollInterval(2, SECONDS);
setDefaultPollDelay(5, SECONDS);
// Minimal logging in production
setLogging(msg -> productionLogger.debug("Awaitility: {}", msg));
// Conservative fail-fast
setDefaultFailFastCondition("Critical system failure",
() -> systemHealth.getOverallStatus() == HealthStatus.CRITICAL);
}
}public class BaseIntegrationTest {
@BeforeEach
public void setupAwaitility() {
// Reset before each test
reset();
// Configure for integration testing
setDefaultTimeout(Duration.ofMinutes(2));
setDefaultPollInterval(Duration.ofMillis(200));
// Enable detailed logging for failed tests
setDefaultConditionEvaluationListener(new ConditionEvaluationListener<Object>() {
@Override
public void onTimeout(TimeoutEvent timeoutEvent) {
logger.error("Awaitility timeout in {}: {} after {}ms",
getCurrentTestMethod(),
timeoutEvent.getDescription(),
timeoutEvent.getElapsedTimeInMS());
}
});
// Global fail-fast for test environment issues
setDefaultFailFastCondition("Test environment unstable", () -> {
return testDatabase.getConnectionPool().getActiveCount() == 0 ||
testMessageBroker.getStatus() != BrokerStatus.RUNNING;
});
}
@AfterEach
public void cleanupAwaitility() {
reset();
}
// Utility methods for common patterns
protected ConditionFactory awaitSlowOperation() {
return await().atMost(Duration.ofMinutes(5))
.pollInterval(Duration.ofSeconds(2))
.logging(msg -> logger.trace("SlowOp: {}", msg));
}
protected ConditionFactory awaitQuickOperation() {
return await().atMost(Duration.ofSeconds(10))
.pollInterval(Duration.ofMillis(50))
.pollDelay(Duration.ofMillis(10));
}
}public class PerformanceAwareAwaitility {
private static final MeterRegistry meterRegistry = Metrics.globalRegistry;
private static final Timer awaitTimer = Timer.builder("awaitility.duration")
.description("Time spent waiting in Awaitility")
.register(meterRegistry);
public static void configureWithMetrics() {
setDefaultConditionEvaluationListener(new ConditionEvaluationListener<Object>() {
private final Map<String, Timer.Sample> samples = new ConcurrentHashMap<>();
@Override
public void beforeEvaluation(StartEvaluationEvent<Object> event) {
Timer.Sample sample = Timer.start(meterRegistry);
samples.put(event.getDescription(), sample);
}
@Override
public void conditionEvaluated(EvaluatedCondition<Object> condition) {
// Record individual evaluation metrics
meterRegistry.counter("awaitility.evaluations.total",
"condition", condition.getDescription(),
"result", String.valueOf(condition.isSatisfied()))
.increment();
}
@Override
public void onTimeout(TimeoutEvent timeoutEvent) {
Timer.Sample sample = samples.remove(timeoutEvent.getDescription());
if (sample != null) {
sample.stop(awaitTimer.tag("result", "timeout"));
}
meterRegistry.counter("awaitility.timeouts.total",
"condition", timeoutEvent.getDescription())
.increment();
}
});
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-awaitility--awaitility