Common test utilities and framework for Quarkus applications, providing core testing infrastructure including application launchers, test isolation, configuration management, and integration with REST Assured for HTTP testing
—
Access to test execution context, Dev Services properties, and test failure status for advanced test scenarios and resource cleanup. These components provide deep integration with the Quarkus test lifecycle and development services.
Represents test execution status with access to failure information for conditional resource cleanup and debugging.
public class TestStatus {
public TestStatus(Throwable testErrorCause) {}
public Throwable getTestErrorCause() {}
public boolean isTestFailed() {}
}Usage in Test Resources:
public class LoggingTestResource implements QuarkusTestResourceLifecycleManager {
private TestStatus testStatus;
@Override
public void setContext(Context context) {
this.testStatus = context.getTestStatus();
}
@Override
public void stop() {
if (testStatus.isTestFailed()) {
// Capture additional logs for failed tests
captureFailureLogs();
Throwable cause = testStatus.getTestErrorCause();
if (cause != null) {
System.err.println("Test failed with: " + cause.getMessage());
cause.printStackTrace();
}
}
}
private void captureFailureLogs() {
// Implementation to capture logs, database state, etc.
System.out.println("Capturing failure diagnostics...");
}
}Provides access to Dev Services properties and container networking information for test resource coordination.
public interface DevServicesContext {
Map<String, String> devServicesProperties();
Optional<String> containerNetworkId();
interface ContextAware {
void setIntegrationTestContext(DevServicesContext context);
}
}Usage Example:
public class DatabaseAwareTestResource implements QuarkusTestResourceLifecycleManager,
DevServicesContext.ContextAware {
private DevServicesContext devServicesContext;
@Override
public void setIntegrationTestContext(DevServicesContext context) {
this.devServicesContext = context;
}
@Override
public Map<String, String> start() {
// Access Dev Services database properties
Map<String, String> devServicesProps = devServicesContext.devServicesProperties();
String dbUrl = devServicesProps.get("quarkus.datasource.jdbc.url");
if (dbUrl != null) {
System.out.println("Using Dev Services database: " + dbUrl);
// Use the same network for additional containers
Optional<String> networkId = devServicesContext.containerNetworkId();
if (networkId.isPresent()) {
return configureWithNetwork(networkId.get());
}
}
return Map.of();
}
private Map<String, String> configureWithNetwork(String networkId) {
// Configure additional test containers to use the same network
// This allows containers to communicate with Dev Services
GenericContainer<?> additionalService = new GenericContainer<>("redis:7")
.withNetwork(Network.newNetwork())
.withExposedPorts(6379);
additionalService.start();
return Map.of(
"quarkus.redis.hosts", "redis://localhost:" + additionalService.getMappedPort(6379)
);
}
}Represents server listening address information for test URL construction and service discovery.
public class ListeningAddress {
public ListeningAddress(Integer port, String protocol) {}
public Integer getPort() {}
public String getProtocol() {}
public boolean isSsl() {}
}Usage Example:
public class ServiceDiscoveryTest {
@Test
public void testServiceEndpoints() {
// Get application listening addresses
ListeningAddress httpAddress = new ListeningAddress(8080, "http");
ListeningAddress httpsAddress = new ListeningAddress(8443, "https");
// Test HTTP endpoint
assertFalse(httpAddress.isSsl());
assertEquals("http", httpAddress.getProtocol());
String httpUrl = httpAddress.getProtocol() + "://localhost:" + httpAddress.getPort();
given()
.baseUri(httpUrl)
.when()
.get("/health")
.then()
.statusCode(200);
// Test HTTPS endpoint
assertTrue(httpsAddress.isSsl());
assertEquals("https", httpsAddress.getProtocol());
String httpsUrl = httpsAddress.getProtocol() + "://localhost:" + httpsAddress.getPort();
given()
.baseUri(httpsUrl)
.relaxedHTTPSValidation()
.when()
.get("/health")
.then()
.statusCode(200);
}
}Using test status for conditional resource management:
public class ConditionalCleanupResource implements QuarkusTestResourceLifecycleManager {
private ExternalService externalService;
private TestStatus testStatus;
@Override
public void setContext(Context context) {
this.testStatus = context.getTestStatus();
}
@Override
public Map<String, String> start() {
externalService = new ExternalService();
externalService.start();
return Map.of(
"external.service.url", externalService.getUrl()
);
}
@Override
public void stop() {
if (testStatus.isTestFailed()) {
// Preserve resources for debugging
System.out.println("Test failed - preserving external service for debugging");
System.out.println("Service URL: " + externalService.getUrl());
System.out.println("Admin URL: " + externalService.getAdminUrl());
// Optionally create debug snapshot
externalService.createDebugSnapshot();
} else {
// Normal cleanup
externalService.stop();
}
}
}Integrating with existing Dev Services containers:
public class DevServicesIntegrationResource implements QuarkusTestResourceLifecycleManager,
DevServicesContext.ContextAware {
private DevServicesContext context;
private GenericContainer<?> additionalContainer;
@Override
public void setIntegrationTestContext(DevServicesContext context) {
this.context = context;
}
@Override
public Map<String, String> start() {
Map<String, String> config = new HashMap<>();
// Get Dev Services properties
Map<String, String> devProps = context.devServicesProperties();
// Check if Dev Services PostgreSQL is running
String dbUrl = devProps.get("quarkus.datasource.jdbc.url");
if (dbUrl != null && dbUrl.contains("postgresql")) {
// Start additional container in same network
Optional<String> networkId = context.containerNetworkId();
if (networkId.isPresent()) {
additionalContainer = new GenericContainer<>("adminer:4")
.withNetwork(Network.newNetwork())
.withExposedPorts(8080)
.withEnv("ADMINER_DEFAULT_SERVER", extractHostFromUrl(dbUrl));
additionalContainer.start();
config.put("adminer.url",
"http://localhost:" + additionalContainer.getMappedPort(8080));
}
}
return config;
}
@Override
public void stop() {
if (additionalContainer != null) {
additionalContainer.stop();
}
}
private String extractHostFromUrl(String jdbcUrl) {
// Extract hostname from JDBC URL for container networking
return jdbcUrl.replaceAll(".*//([^:/]+).*", "$1");
}
}Using test profile information for conditional behavior:
public class ProfileAwareResource implements QuarkusTestResourceLifecycleManager {
private String testProfile;
@Override
public void setContext(Context context) {
this.testProfile = context.testProfile();
}
@Override
public Map<String, String> start() {
Map<String, String> config = new HashMap<>();
switch (testProfile) {
case "integration":
// Start full external services
config.putAll(startIntegrationServices());
break;
case "performance":
// Start monitoring and metrics services
config.putAll(startPerformanceServices());
break;
case "security":
// Start security test services
config.putAll(startSecurityServices());
break;
default:
// Minimal setup for unit tests
config.putAll(startMinimalServices());
}
return config;
}
private Map<String, String> startIntegrationServices() {
// Start database, message broker, external APIs
return Map.of(
"postgres.url", startPostgres(),
"kafka.url", startKafka(),
"external.api.url", startMockAPI()
);
}
private Map<String, String> startPerformanceServices() {
// Start monitoring stack
return Map.of(
"prometheus.url", startPrometheus(),
"grafana.url", startGrafana()
);
}
// Additional profile-specific configurations...
}Coordinating multiple containers with shared networking:
public class MultiContainerResource implements QuarkusTestResourceLifecycleManager,
DevServicesContext.ContextAware {
private DevServicesContext context;
private Network sharedNetwork;
private GenericContainer<?> databaseContainer;
private GenericContainer<?> cacheContainer;
private GenericContainer<?> messageContainer;
@Override
public void setIntegrationTestContext(DevServicesContext context) {
this.context = context;
}
@Override
public Map<String, String> start() {
// Create or reuse network
Optional<String> existingNetwork = context.containerNetworkId();
if (existingNetwork.isPresent()) {
// Use Dev Services network
sharedNetwork = Network.newNetwork();
} else {
// Create new network
sharedNetwork = Network.newNetwork();
}
// Start coordinated containers
Map<String, String> config = new HashMap<>();
config.putAll(startDatabase());
config.putAll(startCache());
config.putAll(startMessageBroker());
return config;
}
private Map<String, String> startDatabase() {
databaseContainer = new PostgreSQLContainer<>("postgres:13")
.withNetwork(sharedNetwork)
.withNetworkAliases("postgres")
.withDatabaseName("testdb");
databaseContainer.start();
return Map.of(
"quarkus.datasource.jdbc.url", databaseContainer.getJdbcUrl(),
"quarkus.datasource.username", databaseContainer.getUsername(),
"quarkus.datasource.password", databaseContainer.getPassword()
);
}
private Map<String, String> startCache() {
cacheContainer = new GenericContainer<>("redis:7")
.withNetwork(sharedNetwork)
.withNetworkAliases("redis")
.withExposedPorts(6379);
cacheContainer.start();
return Map.of(
"quarkus.redis.hosts", "redis://localhost:" + cacheContainer.getMappedPort(6379)
);
}
private Map<String, String> startMessageBroker() {
messageContainer = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0"))
.withNetwork(sharedNetwork)
.withNetworkAliases("kafka");
messageContainer.start();
return Map.of(
"kafka.bootstrap.servers", messageContainer.getBootstrapServers()
);
}
@Override
public void stop() {
if (messageContainer != null) messageContainer.stop();
if (cacheContainer != null) cacheContainer.stop();
if (databaseContainer != null) databaseContainer.stop();
if (sharedNetwork != null) sharedNetwork.close();
}
}Interfaces for detecting when integration tests and native images have started, particularly useful for non-HTTP based applications.
public interface IntegrationTestStartedNotifier {
Result check(Context context);
interface Context {
Path logFile();
}
interface Result {
boolean isStarted();
boolean isSsl();
final class NotStarted implements Result {
public static final NotStarted INSTANCE = new NotStarted();
public boolean isStarted() { return false; }
public boolean isSsl() { return false; }
}
}
}
@Deprecated
public interface NativeImageStartedNotifier {
boolean isNativeImageStarted();
}Usage Example - Custom Integration Test Notifier:
public class CustomStartupNotifier implements IntegrationTestStartedNotifier {
@Override
public Result check(Context context) {
Path logFile = context.logFile();
try {
String logContent = Files.readString(logFile);
// Check for application startup indicators
if (logContent.contains("Application started successfully")) {
// Check if SSL is enabled
boolean sslEnabled = logContent.contains("HTTPS server started");
return new StartedResult(sslEnabled);
}
// Check for startup failure
if (logContent.contains("Application failed to start")) {
throw new RuntimeException("Application startup failed");
}
// Not started yet
return Result.NotStarted.INSTANCE;
} catch (IOException e) {
// Log file not readable yet
return Result.NotStarted.INSTANCE;
}
}
private static class StartedResult implements Result {
private final boolean ssl;
public StartedResult(boolean ssl) {
this.ssl = ssl;
}
@Override
public boolean isStarted() {
return true;
}
@Override
public boolean isSsl() {
return ssl;
}
}
}Service Registration:
Create META-INF/services/io.quarkus.test.common.IntegrationTestStartedNotifier:
com.mycompany.test.CustomStartupNotifierLegacy Native Image Notifier (Deprecated):
@Deprecated
public class LegacyNativeNotifier implements NativeImageStartedNotifier {
@Override
public boolean isNativeImageStarted() {
// Legacy implementation - use IntegrationTestStartedNotifier instead
return checkApplicationProcess();
}
private boolean checkApplicationProcess() {
// Implementation to check if native process is running
return true;
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-test-common