0
# Launcher Infrastructure
1
2
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.
3
4
## Capabilities
5
6
### ArtifactLauncher Interface
7
8
Main interface for launching different types of Quarkus artifacts with lifecycle management and configuration support.
9
10
```java { .api }
11
public interface ArtifactLauncher<T> extends Closeable {
12
void init(T initContext);
13
void start() throws IOException;
14
LaunchResult runToCompletion(String[] args);
15
void includeAsSysProps(Map<String, String> systemProps);
16
boolean listensOnSsl();
17
void close() throws IOException;
18
19
class LaunchResult {
20
public LaunchResult(int statusCode, byte[] output, byte[] stderror) {}
21
public int getStatusCode() {}
22
public byte[] getOutput() {}
23
public byte[] getStderror() {}
24
}
25
26
interface InitContext {
27
int httpPort();
28
int httpsPort();
29
Duration waitTime();
30
String testProfile();
31
List<String> argLine();
32
Map<String, String> env();
33
DevServicesLaunchResult getDevServicesLaunchResult();
34
}
35
}
36
```
37
38
**Basic Usage Pattern:**
39
```java
40
public class ArtifactLauncherTest {
41
@Test
42
public void testJarLauncher() throws IOException {
43
JarArtifactLauncher launcher = new JarArtifactLauncher();
44
45
// Initialize with context
46
InitContext context = new TestInitContext(8080, 8443, Duration.ofSeconds(30));
47
launcher.init(context);
48
49
// Configure system properties
50
launcher.includeAsSysProps(Map.of(
51
"quarkus.test.profile", "integration",
52
"app.environment", "test"
53
));
54
55
try {
56
// Start the application
57
launcher.start();
58
59
// Verify application is running
60
assertTrue(launcher.listensOnSsl()); // if HTTPS configured
61
62
// Run to completion with arguments
63
LaunchResult result = launcher.runToCompletion(new String[]{"--help"});
64
assertEquals(0, result.getStatusCode());
65
66
} finally {
67
launcher.close();
68
}
69
}
70
}
71
```
72
73
### Concrete Launcher Implementations
74
75
#### JarArtifactLauncher
76
77
Launches Quarkus applications packaged as executable JARs.
78
79
```java { .api }
80
public class JarArtifactLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
81
// Implementation for JAR-based artifacts
82
}
83
```
84
85
**Usage Example:**
86
```java
87
@Test
88
public void testJarDeployment() throws IOException {
89
JarArtifactLauncher launcher = new JarArtifactLauncher();
90
InitContext context = createInitContext();
91
92
launcher.init(context);
93
launcher.includeAsSysProps(Map.of(
94
"quarkus.datasource.jdbc.url", "jdbc:h2:mem:test"
95
));
96
97
launcher.start();
98
99
// Test HTTP endpoints
100
given()
101
.baseUri("http://localhost:" + context.httpPort())
102
.when()
103
.get("/health")
104
.then()
105
.statusCode(200);
106
107
launcher.close();
108
}
109
```
110
111
#### NativeImageLauncher
112
113
Launches Quarkus native images for testing native compilation scenarios.
114
115
```java { .api }
116
public class NativeImageLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
117
// Implementation for native image artifacts
118
}
119
```
120
121
**Usage Example:**
122
```java
123
@Test
124
@EnabledIfSystemProperty(named = "native", matches = "true")
125
public void testNativeImage() throws IOException {
126
NativeImageLauncher launcher = new NativeImageLauncher();
127
InitContext context = createInitContext();
128
129
launcher.init(context);
130
launcher.start();
131
132
// Test native image startup time and memory usage
133
long startTime = System.currentTimeMillis();
134
135
// Verify application is responsive
136
given()
137
.baseUri("http://localhost:" + context.httpPort())
138
.when()
139
.get("/api/startup-time")
140
.then()
141
.statusCode(200)
142
.body("startupTime", lessThan(1000)); // Native should start quickly
143
144
launcher.close();
145
}
146
```
147
148
#### DefaultDockerContainerLauncher
149
150
Launches Quarkus applications in Docker containers.
151
152
```java { .api }
153
public class DefaultDockerContainerLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
154
// Implementation for containerized artifacts
155
}
156
```
157
158
**Usage Example:**
159
```java
160
@Test
161
@Testcontainers
162
public void testContainerDeployment() throws IOException {
163
DefaultDockerContainerLauncher launcher = new DefaultDockerContainerLauncher();
164
InitContext context = createInitContext();
165
166
launcher.init(context);
167
launcher.includeAsSysProps(Map.of(
168
"quarkus.container-image.build", "true",
169
"quarkus.container-image.tag", "test"
170
));
171
172
launcher.start();
173
174
// Test containerized application
175
given()
176
.baseUri("http://localhost:" + context.httpPort())
177
.when()
178
.get("/health")
179
.then()
180
.statusCode(200)
181
.body("status", equalTo("UP"));
182
183
launcher.close();
184
}
185
```
186
187
#### RunCommandLauncher
188
189
Launches applications using custom run commands.
190
191
```java { .api }
192
public class RunCommandLauncher implements ArtifactLauncher<ArtifactLauncher.InitContext> {
193
// Implementation for custom command execution
194
}
195
```
196
197
### Supporting Classes
198
199
#### LauncherUtil
200
201
Utility class for common launcher operations and configuration.
202
203
```java { .api }
204
public class LauncherUtil {
205
public static void updateConfigForPort(Path configFile, int port) {}
206
public static boolean isApplicationStarted(String baseUrl, Duration timeout) {}
207
public static void waitForApplicationStart(String baseUrl, Duration timeout) {}
208
// Additional utility methods
209
}
210
```
211
212
**Usage Example:**
213
```java
214
public class LauncherUtilTest {
215
@Test
216
public void testApplicationStartup() {
217
String baseUrl = "http://localhost:8080";
218
Duration timeout = Duration.ofSeconds(30);
219
220
// Wait for application to start
221
LauncherUtil.waitForApplicationStart(baseUrl, timeout);
222
223
// Verify application is ready
224
assertTrue(LauncherUtil.isApplicationStarted(baseUrl, Duration.ofSeconds(5)));
225
}
226
}
227
```
228
229
#### ProcessReader
230
231
Utility for reading process output streams.
232
233
```java { .api }
234
public class ProcessReader {
235
public static void readProcessOutput(Process process, Consumer<String> outputHandler) {}
236
public static String captureOutput(Process process) throws IOException {}
237
// Additional process handling methods
238
}
239
```
240
241
#### NativeImageStartedNotifier
242
243
Specialized utility for detecting native image startup completion.
244
245
```java { .api }
246
public class NativeImageStartedNotifier {
247
public static boolean waitForStartup(Process process, Duration timeout) {}
248
public static void notifyStartupComplete(String signal) {}
249
// Native image specific utilities
250
}
251
```
252
253
## Advanced Usage Patterns
254
255
### Custom Launcher Implementation
256
257
Creating a custom launcher for specific deployment scenarios:
258
259
```java
260
public class CustomKubernetesLauncher implements ArtifactLauncher<InitContext> {
261
private KubernetesClient kubernetesClient;
262
private String deploymentName;
263
264
@Override
265
public void init(InitContext initContext) {
266
this.kubernetesClient = new DefaultKubernetesClient();
267
this.deploymentName = "test-app-" + System.currentTimeMillis();
268
}
269
270
@Override
271
public void start() throws IOException {
272
// Deploy to Kubernetes
273
Deployment deployment = new DeploymentBuilder()
274
.withNewMetadata().withName(deploymentName).endMetadata()
275
.withNewSpec()
276
.withReplicas(1)
277
.withNewTemplate()
278
.withNewSpec()
279
.addNewContainer()
280
.withName("app")
281
.withImage("quarkus-app:test")
282
.addNewPort().withContainerPort(8080).endPort()
283
.endContainer()
284
.endSpec()
285
.endTemplate()
286
.endSpec()
287
.build();
288
289
kubernetesClient.apps().deployments().create(deployment);
290
291
// Wait for deployment to be ready
292
kubernetesClient.apps().deployments()
293
.withName(deploymentName)
294
.waitUntilReady(60, TimeUnit.SECONDS);
295
}
296
297
@Override
298
public void close() throws IOException {
299
if (kubernetesClient != null && deploymentName != null) {
300
kubernetesClient.apps().deployments().withName(deploymentName).delete();
301
}
302
}
303
304
// Implement other required methods...
305
}
306
```
307
308
### Multi-Environment Testing
309
310
Testing across different deployment environments:
311
312
```java
313
@ParameterizedTest
314
@ValueSource(strings = {"jar", "native", "container"})
315
public void testAcrossEnvironments(String launcherType) throws IOException {
316
ArtifactLauncher<?> launcher = createLauncher(launcherType);
317
InitContext context = createInitContext();
318
319
launcher.init(context);
320
launcher.start();
321
322
try {
323
// Common test logic for all environments
324
verifyHealthEndpoint(context.httpPort());
325
verifyAPIEndpoints(context.httpPort());
326
verifyMetrics(context.httpPort());
327
328
} finally {
329
launcher.close();
330
}
331
}
332
333
private ArtifactLauncher<?> createLauncher(String type) {
334
return switch (type) {
335
case "jar" -> new JarArtifactLauncher();
336
case "native" -> new NativeImageLauncher();
337
case "container" -> new DefaultDockerContainerLauncher();
338
default -> throw new IllegalArgumentException("Unknown launcher type: " + type);
339
};
340
}
341
```
342
343
### Performance Testing with Launchers
344
345
Measuring application performance across different deployment modes:
346
347
```java
348
public class PerformanceTest {
349
@Test
350
public void compareStartupTimes() throws IOException {
351
Map<String, Duration> startupTimes = new HashMap<>();
352
353
// Test JAR startup
354
startupTimes.put("JAR", measureStartupTime(new JarArtifactLauncher()));
355
356
// Test native image startup
357
startupTimes.put("Native", measureStartupTime(new NativeImageLauncher()));
358
359
// Verify native is faster
360
assertTrue(startupTimes.get("Native").compareTo(startupTimes.get("JAR")) < 0,
361
"Native image should start faster than JAR");
362
363
System.out.println("Startup times: " + startupTimes);
364
}
365
366
private Duration measureStartupTime(ArtifactLauncher<?> launcher) throws IOException {
367
InitContext context = createInitContext();
368
launcher.init(context);
369
370
long start = System.currentTimeMillis();
371
launcher.start();
372
373
// Wait for application to be responsive
374
LauncherUtil.waitForApplicationStart(
375
"http://localhost:" + context.httpPort(),
376
Duration.ofSeconds(60)
377
);
378
379
long end = System.currentTimeMillis();
380
launcher.close();
381
382
return Duration.ofMillis(end - start);
383
}
384
}
385
```
386
387
### Resource Monitoring
388
389
Monitoring resource usage during testing:
390
391
```java
392
public class ResourceMonitoringTest {
393
@Test
394
public void monitorResourceUsage() throws IOException {
395
JarArtifactLauncher launcher = new JarArtifactLauncher();
396
InitContext context = createInitContext();
397
398
launcher.init(context);
399
launcher.start();
400
401
try {
402
// Monitor memory usage
403
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
404
long initialMemory = memoryBean.getHeapMemoryUsage().getUsed();
405
406
// Simulate load
407
IntStream.range(0, 1000).parallel().forEach(i -> {
408
given()
409
.baseUri("http://localhost:" + context.httpPort())
410
.when()
411
.get("/api/data/" + i)
412
.then()
413
.statusCode(200);
414
});
415
416
long finalMemory = memoryBean.getHeapMemoryUsage().getUsed();
417
long memoryIncrease = finalMemory - initialMemory;
418
419
System.out.println("Memory increase: " + memoryIncrease + " bytes");
420
assertTrue(memoryIncrease < 100_000_000, "Memory usage should be reasonable");
421
422
} finally {
423
launcher.close();
424
}
425
}
426
}
427
```