Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Quarkus CLI tests #1164

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading