CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkus--quarkus-test-common

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

Pending
Overview
Eval results
Files

launchers.mddocs/

Launcher Infrastructure

Interfaces and implementations for launching and managing different types of Quarkus artifacts during testing, including JVM, native image, and containerized deployments. The launcher system provides a unified interface for testing applications across various runtime environments.

Capabilities

ArtifactLauncher Interface

Main interface for launching different types of Quarkus artifacts with lifecycle management and configuration support.

public interface ArtifactLauncher<T> extends Closeable {
    void init(T initContext);
    void start() throws IOException;
    LaunchResult runToCompletion(String[] args);
    void includeAsSysProps(Map<String, String> systemProps);
    boolean listensOnSsl();
    void close() throws IOException;
    
    class LaunchResult {
        public LaunchResult(int statusCode, byte[] output, byte[] stderror) {}
        public int getStatusCode() {}
        public byte[] getOutput() {}
        public byte[] getStderror() {}
    }
    
    interface InitContext {
        int httpPort();
        int httpsPort();
        Duration waitTime();
        String testProfile();
        List<String> argLine();
        Map<String, String> env();
        DevServicesLaunchResult getDevServicesLaunchResult();
    }
}

Basic Usage Pattern:

public class ArtifactLauncherTest {
    @Test
    public void testJarLauncher() throws IOException {
        JarArtifactLauncher launcher = new JarArtifactLauncher();
        
        // Initialize with context
        InitContext context = new TestInitContext(8080, 8443, Duration.ofSeconds(30));
        launcher.init(context);
        
        // Configure system properties
        launcher.includeAsSysProps(Map.of(
            "quarkus.test.profile", "integration",
            "app.environment", "test"
        ));
        
        try {
            // Start the application
            launcher.start();
            
            // Verify application is running
            assertTrue(launcher.listensOnSsl()); // if HTTPS configured
            
            // Run to completion with arguments
            LaunchResult result = launcher.runToCompletion(new String[]{"--help"});
            assertEquals(0, result.getStatusCode());
            
        } finally {
            launcher.close();
        }
    }
}

Concrete Launcher Implementations

JarArtifactLauncher

Launches Quarkus applications packaged as executable JARs.

public class JarArtifactLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
    // Implementation for JAR-based artifacts
}

Usage Example:

@Test
public void testJarDeployment() throws IOException {
    JarArtifactLauncher launcher = new JarArtifactLauncher();
    InitContext context = createInitContext();
    
    launcher.init(context);
    launcher.includeAsSysProps(Map.of(
        "quarkus.datasource.jdbc.url", "jdbc:h2:mem:test"
    ));
    
    launcher.start();
    
    // Test HTTP endpoints
    given()
        .baseUri("http://localhost:" + context.httpPort())
    .when()
        .get("/health")
    .then()
        .statusCode(200);
    
    launcher.close();
}

NativeImageLauncher

Launches Quarkus native images for testing native compilation scenarios.

public class NativeImageLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
    // Implementation for native image artifacts  
}

Usage Example:

@Test
@EnabledIfSystemProperty(named = "native", matches = "true")
public void testNativeImage() throws IOException {
    NativeImageLauncher launcher = new NativeImageLauncher();
    InitContext context = createInitContext();
    
    launcher.init(context);
    launcher.start();
    
    // Test native image startup time and memory usage
    long startTime = System.currentTimeMillis();
    
    // Verify application is responsive
    given()
        .baseUri("http://localhost:" + context.httpPort())
    .when()
        .get("/api/startup-time")
    .then()
        .statusCode(200)
        .body("startupTime", lessThan(1000)); // Native should start quickly
    
    launcher.close();
}

DefaultDockerContainerLauncher

Launches Quarkus applications in Docker containers.

public class DefaultDockerContainerLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
    // Implementation for containerized artifacts
}

Usage Example:

@Test
@Testcontainers
public void testContainerDeployment() throws IOException {
    DefaultDockerContainerLauncher launcher = new DefaultDockerContainerLauncher();
    InitContext context = createInitContext();
    
    launcher.init(context);
    launcher.includeAsSysProps(Map.of(
        "quarkus.container-image.build", "true",
        "quarkus.container-image.tag", "test"
    ));
    
    launcher.start();
    
    // Test containerized application
    given()
        .baseUri("http://localhost:" + context.httpPort())
    .when()
        .get("/health")
    .then()
        .statusCode(200)
        .body("status", equalTo("UP"));
    
    launcher.close();
}

RunCommandLauncher

Launches applications using custom run commands.

public class RunCommandLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
    // Implementation for custom command execution
}

Supporting Classes

LauncherUtil

Utility class for common launcher operations and configuration.

public class LauncherUtil {
    public static void updateConfigForPort(Path configFile, int port) {}
    public static boolean isApplicationStarted(String baseUrl, Duration timeout) {}
    public static void waitForApplicationStart(String baseUrl, Duration timeout) {}
    // Additional utility methods
}

Usage Example:

public class LauncherUtilTest {
    @Test
    public void testApplicationStartup() {
        String baseUrl = "http://localhost:8080";
        Duration timeout = Duration.ofSeconds(30);
        
        // Wait for application to start
        LauncherUtil.waitForApplicationStart(baseUrl, timeout);
        
        // Verify application is ready
        assertTrue(LauncherUtil.isApplicationStarted(baseUrl, Duration.ofSeconds(5)));
    }
}

ProcessReader

Utility for reading process output streams.

public class ProcessReader {
    public static void readProcessOutput(Process process, Consumer<String> outputHandler) {}
    public static String captureOutput(Process process) throws IOException {}
    // Additional process handling methods
}

NativeImageStartedNotifier

Specialized utility for detecting native image startup completion.

public class NativeImageStartedNotifier {
    public static boolean waitForStartup(Process process, Duration timeout) {}
    public static void notifyStartupComplete(String signal) {}
    // Native image specific utilities
}

Advanced Usage Patterns

Custom Launcher Implementation

Creating a custom launcher for specific deployment scenarios:

public class CustomKubernetesLauncher implements ArtifactLauncher<InitContext> {
    private KubernetesClient kubernetesClient;
    private String deploymentName;
    
    @Override
    public void init(InitContext initContext) {
        this.kubernetesClient = new DefaultKubernetesClient();
        this.deploymentName = "test-app-" + System.currentTimeMillis();
    }
    
    @Override
    public void start() throws IOException {
        // Deploy to Kubernetes
        Deployment deployment = new DeploymentBuilder()
            .withNewMetadata().withName(deploymentName).endMetadata()
            .withNewSpec()
                .withReplicas(1)
                .withNewTemplate()
                    .withNewSpec()
                        .addNewContainer()
                            .withName("app")
                            .withImage("quarkus-app:test")
                            .addNewPort().withContainerPort(8080).endPort()
                        .endContainer()
                    .endSpec()
                .endTemplate()
            .endSpec()
            .build();
        
        kubernetesClient.apps().deployments().create(deployment);
        
        // Wait for deployment to be ready
        kubernetesClient.apps().deployments()
            .withName(deploymentName)
            .waitUntilReady(60, TimeUnit.SECONDS);
    }
    
    @Override
    public void close() throws IOException {
        if (kubernetesClient != null && deploymentName != null) {
            kubernetesClient.apps().deployments().withName(deploymentName).delete();
        }
    }
    
    // Implement other required methods...
}

Multi-Environment Testing

Testing across different deployment environments:

@ParameterizedTest
@ValueSource(strings = {"jar", "native", "container"})
public void testAcrossEnvironments(String launcherType) throws IOException {
    ArtifactLauncher<?> launcher = createLauncher(launcherType);
    InitContext context = createInitContext();
    
    launcher.init(context);
    launcher.start();
    
    try {
        // Common test logic for all environments
        verifyHealthEndpoint(context.httpPort());
        verifyAPIEndpoints(context.httpPort());
        verifyMetrics(context.httpPort());
        
    } finally {
        launcher.close();
    }
}

private ArtifactLauncher<?> createLauncher(String type) {
    return switch (type) {
        case "jar" -> new JarArtifactLauncher();
        case "native" -> new NativeImageLauncher();
        case "container" -> new DefaultDockerContainerLauncher();
        default -> throw new IllegalArgumentException("Unknown launcher type: " + type);
    };
}

Performance Testing with Launchers

Measuring application performance across different deployment modes:

public class PerformanceTest {
    @Test
    public void compareStartupTimes() throws IOException {
        Map<String, Duration> startupTimes = new HashMap<>();
        
        // Test JAR startup
        startupTimes.put("JAR", measureStartupTime(new JarArtifactLauncher()));
        
        // Test native image startup  
        startupTimes.put("Native", measureStartupTime(new NativeImageLauncher()));
        
        // Verify native is faster
        assertTrue(startupTimes.get("Native").compareTo(startupTimes.get("JAR")) < 0,
            "Native image should start faster than JAR");
        
        System.out.println("Startup times: " + startupTimes);
    }
    
    private Duration measureStartupTime(ArtifactLauncher<?> launcher) throws IOException {
        InitContext context = createInitContext();
        launcher.init(context);
        
        long start = System.currentTimeMillis();
        launcher.start();
        
        // Wait for application to be responsive
        LauncherUtil.waitForApplicationStart(
            "http://localhost:" + context.httpPort(), 
            Duration.ofSeconds(60)
        );
        
        long end = System.currentTimeMillis();
        launcher.close();
        
        return Duration.ofMillis(end - start);
    }
}

Resource Monitoring

Monitoring resource usage during testing:

public class ResourceMonitoringTest {
    @Test
    public void monitorResourceUsage() throws IOException {
        JarArtifactLauncher launcher = new JarArtifactLauncher();
        InitContext context = createInitContext();
        
        launcher.init(context);
        launcher.start();
        
        try {
            // Monitor memory usage
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            long initialMemory = memoryBean.getHeapMemoryUsage().getUsed();
            
            // Simulate load
            IntStream.range(0, 1000).parallel().forEach(i -> {
                given()
                    .baseUri("http://localhost:" + context.httpPort())
                .when()
                    .get("/api/data/" + i)
                .then()
                    .statusCode(200);
            });
            
            long finalMemory = memoryBean.getHeapMemoryUsage().getUsed();
            long memoryIncrease = finalMemory - initialMemory;
            
            System.out.println("Memory increase: " + memoryIncrease + " bytes");
            assertTrue(memoryIncrease < 100_000_000, "Memory usage should be reasonable");
            
        } finally {
            launcher.close();
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkus--quarkus-test-common

docs

http-testing.md

index.md

launchers.md

test-annotations.md

test-context.md

test-resources.md

utilities.md

tile.json