Skip to content

Commit

Permalink
Refactor Quarkus CLI tests
Browse files Browse the repository at this point in the history
  • Loading branch information
michalvavrik committed Jun 6, 2024
1 parent fe683bd commit 97f0d1a
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 167 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package io.quarkus.qe;

import static io.quarkus.test.bootstrap.QuarkusCliClient.CreateApplicationRequest.defaults;
import static io.quarkus.test.utils.AwaitilityUtils.untilAsserted;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import jakarta.inject.Inject;
Expand All @@ -19,23 +19,34 @@
import io.quarkus.test.bootstrap.QuarkusCliDefaultService;
import io.quarkus.test.bootstrap.QuarkusCliRestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.scenarios.annotations.EnabledOnNative;
import io.quarkus.test.services.quarkus.model.QuarkusProperties;

@Tag("quarkus-cli")
@QuarkusScenario
public class QuarkusCliClientIT {

static final String REST_SPRING_WEB_EXTENSION = "quarkus-spring-web";
static final String REST_EXTENSION = "quarkus-rest";
static final String REST_JACKSON_EXTENSION = "quarkus-rest-jackson";
static final String SMALLRYE_HEALTH_EXTENSION = "quarkus-smallrye-health";
static final int CMD_DELAY_SEC = 3;

@Inject
static QuarkusCliClient cliClient;

@Test
public void shouldVersionMatchQuarkusVersion() {
// Using option
assertEquals(QuarkusProperties.getVersion(), cliClient.run("--version").getOutput());

// Using shortcut
assertEquals(QuarkusProperties.getVersion(), cliClient.run("-v").getOutput());
}

@Test
public void shouldCreateApplicationOnJvm() {
// Create application
QuarkusCliRestService app = cliClient.createApplication("app",
QuarkusCliClient.CreateApplicationRequest.defaults());
QuarkusCliRestService app = cliClient.createApplication("app");

// Should build on Jvm
QuarkusCliClient.Result result = app.buildOnJvm();
Expand All @@ -46,11 +57,36 @@ public void shouldCreateApplicationOnJvm() {
app.given().get().then().statusCode(HttpStatus.SC_OK);
}

@Test
@EnabledOnNative
public void shouldBuildApplicationOnNativeUsingDocker() {
// Create application
QuarkusCliRestService app = cliClient.createApplication("app");

// Should build on Native
QuarkusCliClient.Result result = app.buildOnNative();
assertTrue(result.isSuccessful(),
"The application didn't build on Native. Output: " + result.getOutput());
}

@Test
public void shouldCreateApplicationWithCodeStarter() {
// Create application with Resteasy Jackson
QuarkusCliRestService app = cliClient.createApplication("app", defaults()
.withExtensions(REST_SPRING_WEB_EXTENSION, REST_JACKSON_EXTENSION));

// Verify By default, it installs only "quarkus-resteasy"
assertInstalledExtensions(app, REST_SPRING_WEB_EXTENSION, REST_JACKSON_EXTENSION);

// Start using DEV mode
app.start();
untilAsserted(() -> app.given().get("/greeting").then().statusCode(HttpStatus.SC_OK).and().body(is("Hello Spring")));
}

@Test
public void shouldCreateExtension() {
// Create extension
QuarkusCliDefaultService app = cliClient.createExtension("extension-abc",
QuarkusCliClient.CreateExtensionRequest.defaults());
QuarkusCliDefaultService app = cliClient.createExtension("extension-abc");

// Should build on Jvm
QuarkusCliClient.Result result = app.buildOnJvm();
Expand All @@ -59,19 +95,17 @@ public void shouldCreateExtension() {

@Test
public void shouldCreateApplicationUsingArtifactId() {
QuarkusCliRestService app = cliClient.createApplication("com.mycompany:my-app",
QuarkusCliClient.CreateApplicationRequest.defaults());
QuarkusCliRestService app = cliClient.createApplication("com.mycompany:my-app");
assertEquals("my-app", app.getServiceFolder().getFileName().toString(), "The application directory differs.");

QuarkusCliClient.Result result = app.buildOnJvm();
assertTrue(result.isSuccessful(), "The application didn't build on JVM. Output: " + result.getOutput());
}

@Test
public void shouldAddAndRemoveExtensions() throws InterruptedException {
public void shouldAddAndRemoveExtensions() {
// Create application
QuarkusCliRestService app = cliClient.createApplication("app",
QuarkusCliClient.CreateApplicationRequest.defaults());
QuarkusCliRestService app = cliClient.createApplication("app");

// By default, it installs only "quarkus-rest"
assertInstalledExtensions(app, REST_EXTENSION);
Expand All @@ -93,19 +127,20 @@ public void shouldAddAndRemoveExtensions() throws InterruptedException {
assertTrue(result.isSuccessful(), SMALLRYE_HEALTH_EXTENSION + " was not uninstalled. Output: " + result.getOutput());

// The health endpoint should be now gone
startAfter(app, Duration.ofSeconds(CMD_DELAY_SEC));
app.start();
untilAsserted(() -> app.given().get("/q/health").then().statusCode(HttpStatus.SC_NOT_FOUND));
}

@Test
public void shouldListExtensionsUsingDefaults() {
var result = cliClient.listExtensions();
assertTrue(result.getOutput().contains("quarkus-rest-jackson"),
"Listed extensions should contain quarkus-rest-jackson: " + result.getOutput());
}

private void assertInstalledExtensions(QuarkusCliRestService app, String... expectedExtensions) {
List<String> extensions = app.getInstalledExtensions();
Stream.of(expectedExtensions).forEach(expectedExtension -> assertTrue(extensions.contains(expectedExtension),
expectedExtension + " not found in " + extensions));
}

// https://github.com/quarkusio/quarkus/issues/21070
private void startAfter(QuarkusCliRestService app, Duration duration) throws InterruptedException {
TimeUnit.SECONDS.sleep(duration.getSeconds());
app.start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand All @@ -27,6 +29,7 @@ public class QuarkusCliClient {
public static final String COMMAND_LOG_FILE = "quarkus-cli-command.out";
public static final String DEV_MODE_LOG_FILE = "quarkus-cli-dev.out";

private static final String QUARKUS_UPSTREAM_VERSION = "999-SNAPSHOT";
private static final String BUILD = "build";
private static final PropertyLookup COMMAND = new PropertyLookup("ts.quarkus.cli.cmd", "quarkus");
private static final Path TARGET = Paths.get("target");
Expand Down Expand Up @@ -69,12 +72,22 @@ public Process runOnDev(Path servicePath, File logOutput, Map<String, String> ar
return runCli(servicePath, logOutput, cmd.toArray(new String[cmd.size()]));
}

public QuarkusCliRestService createApplicationAt(String name, String targetFolderName) {
Objects.requireNonNull(targetFolderName);
return createApplication(name, CreateApplicationRequest.defaults(), targetFolderName);
}

public QuarkusCliRestService createApplication(String name) {
return createApplication(name, CreateApplicationRequest.defaults());
}

public QuarkusCliRestService createApplication(String name, CreateApplicationRequest request) {
QuarkusCliRestService service = new QuarkusCliRestService(this);
return createApplication(name, request, null);
}

public QuarkusCliRestService createApplication(String name, CreateApplicationRequest request, String targetFolderName) {
Path serviceFolder = isNotEmpty(targetFolderName) ? TARGET.resolve(targetFolderName).resolve(name) : null;
QuarkusCliRestService service = new QuarkusCliRestService(this, serviceFolder);
ServiceContext serviceContext = service.register(name, context);

service.init(s -> new CliDevModeLocalhostQuarkusApplicationManagedResource(serviceContext, this));
Expand All @@ -83,8 +96,7 @@ public QuarkusCliRestService createApplication(String name, CreateApplicationReq
FileUtils.deletePath(serviceContext.getServiceFolder());

// Generate project
List<String> args = new ArrayList<>();
args.addAll(Arrays.asList("create", "app", name));
List<String> args = new ArrayList<>(Arrays.asList("create", "app", name));
// Platform Bom
if (isNotEmpty(request.platformBom)) {
args.add("--platform-bom=" + request.platformBom);
Expand Down Expand Up @@ -189,6 +201,45 @@ private Process runCli(Path workingDirectory, File logOutput, String... args) {
}
}

private static boolean isUpstream() {
return isUpstream(QuarkusProperties.getVersion());
}

private static boolean isUpstream(String version) {
return version.contains(QUARKUS_UPSTREAM_VERSION);
}

private static String getFixedStreamVersion() {
var rawVersion = QuarkusProperties.getVersion();
if (isUpstream(rawVersion)) {
throw new IllegalStateException("Cannot set fixed stream version for '%s' as it doesn't exist" + rawVersion);
}

String[] version = rawVersion.split(Pattern.quote("."));
return String.format("%s.%s", version[0], version[1]);
}

private static String getCurrentPlatformBom() {
return QuarkusProperties.PLATFORM_GROUP_ID.get() + "::" + QuarkusProperties.getVersion();
}

public Result listExtensions(String... extraArgs) {
return listExtensions(ListExtensionRequest.defaults(), extraArgs);
}

public Result listExtensions(ListExtensionRequest request, String... extraArgs) {
List<String> args = new ArrayList<>();
args.add("extension");
args.add("list");
args.addAll(Arrays.asList(extraArgs));
if (request.stream() != null) {
args.addAll(Arrays.asList("--stream", request.stream()));
}
var result = run(args.toArray(String[]::new));
assertTrue(result.isSuccessful(), "Extensions list command didn't work. Output: " + result.getOutput());
return result;
}

public static class CreateApplicationRequest {
private String platformBom;
private String stream;
Expand All @@ -200,6 +251,10 @@ public CreateApplicationRequest withPlatformBom(String platformBom) {
return this;
}

public CreateApplicationRequest withCurrentPlatformBom() {
return withPlatformBom(getCurrentPlatformBom());
}

public CreateApplicationRequest withStream(String stream) {
this.stream = stream;
return this;
Expand All @@ -216,10 +271,12 @@ public CreateApplicationRequest withExtraArgs(String... extraArgs) {
}

public static CreateApplicationRequest defaults() {
if (QuarkusProperties.getVersion().contains("SNAPSHOT")) {
return new CreateApplicationRequest().withPlatformBom("io.quarkus::" + QuarkusProperties.getVersion());
if (isUpstream()) {
// set platform due to https://github.com/quarkusio/quarkus/issues/40951#issuecomment-2147399201
return new CreateApplicationRequest().withCurrentPlatformBom();
}
return new CreateApplicationRequest();
// set fixed stream because if tested stream is not the latest stream, we would create app with wrong version
return new CreateApplicationRequest().withStream(getFixedStreamVersion());
}
}

Expand All @@ -228,6 +285,10 @@ public static class CreateExtensionRequest {
private String stream;
private String[] extraArgs;

public CreateExtensionRequest withCurrentPlatformBom() {
return withPlatformBom(getCurrentPlatformBom());
}

public CreateExtensionRequest withPlatformBom(String platformBom) {
this.platformBom = platformBom;
return this;
Expand All @@ -244,7 +305,11 @@ public CreateExtensionRequest withExtraArgs(String... extraArgs) {
}

public static CreateExtensionRequest defaults() {
return new CreateExtensionRequest();
if (isUpstream()) {
return new CreateExtensionRequest();
}
// set fixed stream because if tested stream is not the latest stream, we would create app with wrong version
return new CreateExtensionRequest().withStream(getFixedStreamVersion());
}
}

Expand All @@ -267,4 +332,14 @@ public boolean isSuccessful() {
return EXIT_SUCCESS == exitCode;
}
}

public record ListExtensionRequest(String stream) {
public static ListExtensionRequest defaults() {
return new ListExtensionRequest(isUpstream() ? null : getFixedStreamVersion());
}

public static ListExtensionRequest withSetStream() {
return new ListExtensionRequest(isUpstream() ? QUARKUS_UPSTREAM_VERSION : getFixedStreamVersion());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class QuarkusCliRestService extends RestService {

private final QuarkusCliClient cliClient;
private final Path serviceFolder;

public QuarkusCliRestService(QuarkusCliClient cliClient) {
public QuarkusCliRestService(QuarkusCliClient cliClient, Path serviceFolder) {
this.cliClient = cliClient;
this.serviceFolder = serviceFolder;
}

public QuarkusCliClient.Result buildOnJvm(String... extraArgs) {
Expand All @@ -36,4 +42,28 @@ public List<String> getInstalledExtensions() {
.map(line -> line.replace("✬ ", "")).collect(Collectors.toList());
}

public File getFileFromApplication(String fileName) {
// get file from the service folder
return getFileFromApplication("", fileName);
}

public File getFileFromApplication(String subFolder, String fileName) {
Path fileFolderPath = getServiceFolder();
if (subFolder != null && !subFolder.isEmpty()) {
fileFolderPath = Path.of(fileFolderPath.toString(), subFolder);
}

return Arrays.stream(Objects.requireNonNull(fileFolderPath.toFile().listFiles()))
.filter(f -> f.getName().equalsIgnoreCase(fileName))
.findFirst()
.orElseThrow(() -> new RuntimeException(fileName + " not found."));
}

@Override
protected ServiceContext createServiceContext(ScenarioContext context) {
if (serviceFolder != null) {
return new ServiceContext(this, context, serviceFolder);
}
return super.createServiceContext(context);
}
}
Loading

0 comments on commit 97f0d1a

Please sign in to comment.