diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java index 1b57c9aa9ab57..de09063b148bb 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java @@ -18,6 +18,7 @@ import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.util.ArrayList; @@ -936,11 +937,14 @@ Set checkForFileChange(Function checkForFileChange(Function checkForFileChange(Function checkForFileChange(Function last) { // Use either the absolute path or the OS-agnostic path to match the HotDeploymentWatchedFileBuildItem ret.add(isAbsolute ? watchedPath.filePath.toString() : watchedPath.getOSAgnosticMatchPath()); @@ -1372,7 +1380,8 @@ private boolean isAbsolute() { @Override public String toString() { - return "WatchedPath [matchPath=" + matchPath + ", filePath=" + filePath + ", restartNeeded=" + restartNeeded + "]"; + return "WatchedPath [matchPath=" + matchPath + ", filePath=" + filePath + ", restartNeeded=" + restartNeeded + + ", lastModified=" + lastModified + "]"; } } diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java index 39fd504562a81..262bc40ceab09 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java @@ -3,8 +3,6 @@ import static io.quarkus.maven.it.ApplicationNameAndVersionTestUtil.assertApplicationPropertiesSetCorrectly; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -943,37 +941,6 @@ public void testThatExternalConfigOverridesConfigInJar() throws MavenInvocationE .until(() -> devModeClient.getHttpResponse("/app/hello/greeting").contains(uuid)); } - @Test - public void testThatNewResourcesAreServed() throws MavenInvocationException, IOException { - testDir = initProject("projects/classic", "projects/project-classic-run-resource-change"); - runAndCheck(); - - // Create a new resource - File source = new File(testDir, "src/main/resources/META-INF/resources/lorem.txt"); - FileUtils.write(source, - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - "UTF-8"); - await() - .pollDelay(100, TimeUnit.MILLISECONDS) - .atMost(TestUtils.getDefaultTimeout(), TimeUnit.MINUTES) - .until(() -> devModeClient.getHttpResponse("/lorem.txt"), containsString("Lorem ipsum")); - - // Update the resource - String uuid = UUID.randomUUID().toString(); - FileUtils.write(source, uuid, "UTF-8"); - await() - .pollDelay(100, TimeUnit.MILLISECONDS) - .atMost(TestUtils.getDefaultTimeout(), TimeUnit.MINUTES) - .until(() -> devModeClient.getHttpResponse("/lorem.txt"), equalTo(uuid)); - - // Delete the resource - source.delete(); - await() - .pollDelay(100, TimeUnit.MILLISECONDS) - .atMost(TestUtils.getDefaultTimeout(), TimeUnit.MINUTES) - .until(() -> devModeClient.getHttpResponse("/lorem.txt", 404)); - } - @Test public void testThatConfigFileDeletionsAreDetected() throws MavenInvocationException, IOException { testDir = initProject("projects/dev-mode-file-deletion"); diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/FlakyDevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/FlakyDevMojoIT.java new file mode 100644 index 0000000000000..a2b4beaacf714 --- /dev/null +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/FlakyDevMojoIT.java @@ -0,0 +1,55 @@ +package io.quarkus.maven.it; + +import static org.awaitility.Awaitility.await; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.apache.maven.shared.invoker.MavenInvocationException; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.devmode.util.DevModeClient; + +/** + * This test has been isolated as it is very flaky and causing issues with Develocity PTS. + */ +@DisableForNative +public class FlakyDevMojoIT extends RunAndCheckMojoTestBase { + + protected DevModeClient devModeClient = new DevModeClient(getPort()); + + @Test + public void testThatNewResourcesAreServed() throws MavenInvocationException, IOException { + testDir = initProject("projects/classic-with-log", "projects/project-classic-run-resource-change"); + runAndCheck(); + + // Create a new resource + Path source = testDir.toPath().resolve("src/main/resources/META-INF/resources/lorem.txt"); + Files.writeString(source, + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); + await() + .pollDelay(100, TimeUnit.MILLISECONDS) + .atMost(TestUtils.getDefaultTimeout(), TimeUnit.MINUTES) + .until(() -> devModeClient.getHttpResponse("/lorem.txt"), containsString("Lorem ipsum")); + + // Update the resource + String uuid = UUID.randomUUID().toString(); + Files.writeString(source, uuid); + await() + .pollDelay(100, TimeUnit.MILLISECONDS) + .atMost(TestUtils.getDefaultTimeout(), TimeUnit.MINUTES) + .until(() -> devModeClient.getHttpResponse("/lorem.txt"), equalTo(uuid)); + + // Delete the resource + Files.delete(source); + await() + .pollDelay(100, TimeUnit.MILLISECONDS) + .atMost(TestUtils.getDefaultTimeout(), TimeUnit.MINUTES) + .until(() -> devModeClient.getHttpResponse("/lorem.txt", 404)); + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/.env b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/.env new file mode 100644 index 0000000000000..98fb9ae1398c6 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/.env @@ -0,0 +1 @@ +OTHER_GREETING=Hola \ No newline at end of file diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/pom.xml new file mode 100644 index 0000000000000..6e8f3dfe1026f --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/pom.xml @@ -0,0 +1,108 @@ + + + 4.0.0 + org.acme + acme + 1.0-SNAPSHOT + + io.quarkus + quarkus-bom + @project.version@ + @project.version@ + ${compiler-plugin.version} + UTF-8 + ${maven.compiler.source} + ${maven.compiler.target} + + + 1.13.0 + + + + + + \${quarkus.platform.group-id} + \${quarkus.platform.artifact-id} + \${quarkus.platform.version} + pom + import + + + + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-smallrye-context-propagation + + + io.quarkus + quarkus-websockets + + + io.smallrye.common + smallrye-common-vertx-context + 1.13.2 + + + org.webjars + jquery-ui + \${webjar.jquery-ui.version} + + + commons-io + commons-io + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + maven-compiler-plugin + \${compiler-plugin.version} + + + io.quarkus + quarkus-maven-plugin + \${quarkus-plugin.version} + + + + generate-code + generate-code-tests + build + + + + + + + + + native + + true + + + + customOutputDir + + target-other + + + + diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/ClasspathResources.java b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/ClasspathResources.java new file mode 100644 index 0000000000000..a8a4efacded05 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/ClasspathResources.java @@ -0,0 +1,195 @@ +package org.acme; + +import jakarta.ws.rs.QueryParam; +import org.apache.commons.io.IOUtils; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.function.Supplier; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +@Path("/classpathResources") +public class ClasspathResources { + + private static final String SUCCESS = "success"; + + @GET + public String readClassPathResources() { + return runAssertions( + () -> assertInvalidExactFileLocation(), + () -> assertCorrectExactFileLocation(), + () -> assertInvalidDirectory(), + () -> assertCorrectDirectory(), + () -> assertTopLevelDirectory(), + () -> assertMultiRelease() + ); + } + + private String runAssertions(Supplier... assertions) { + String result; + for (Supplier assertion : assertions) { + result = assertion.get(); + if (!SUCCESS.equals(result)) { + return result; + } + } + return SUCCESS; + } + + private String assertInvalidExactFileLocation() { + final String testType = "invalid-exact-location"; + try { + Enumeration exactFileLocationEnumeration = this.getClass().getClassLoader().getResources("db/location/test2.sql"); + List exactFileLocationList = urlList(exactFileLocationEnumeration); + if (exactFileLocationList.size() != 0) { + return errorResult(testType, "wrong number of urls"); + } + return SUCCESS; + } catch (Exception e) { + e.printStackTrace(); + return errorResult(testType, "exception during resolution of resource"); + } + } + + private String assertMultiRelease() { + final String testType = "assert-multi-release-jar"; + if (System.getProperty("java.version").startsWith("1.")) { + return SUCCESS; + } + try { + //this class is only present in multi release jars + //for fast-jar we need to make sure it is loaded correctly + Class clazz = this.getClass().getClassLoader().loadClass("io.smallrye.common.vertx.VertxContext"); + if (clazz.getClassLoader() == getClass().getClassLoader()) { + return SUCCESS; + } + return errorResult(testType, "Incorrect ClassLoader for " + clazz); + } catch (Exception e) { + e.printStackTrace(); + return errorResult(testType, "exception during resolution of resource"); + } + } + private String assertCorrectExactFileLocation() { + final String testType = "correct-exact-location"; + try { + Enumeration exactFileLocationEnumeration = this.getClass().getClassLoader().getResources("db/location/test.sql"); + List exactFileLocationList = urlList(exactFileLocationEnumeration); + if (exactFileLocationList.size() != 1) { + return errorResult(testType, "wrong number of urls"); + } + String fileContent = IOUtils.toString(exactFileLocationList.get(0).toURI(), StandardCharsets.UTF_8); + if (!fileContent.contains("CREATE TABLE")) { + return errorResult(testType, "wrong file content"); + } + return SUCCESS; + } catch (Exception e) { + e.printStackTrace(); + return errorResult(testType, "exception during resolution of resource"); + } + } + + private String assertInvalidDirectory() { + final String testType = "invalid-directory"; + try { + Enumeration exactFileLocationEnumeration = this.getClass().getClassLoader().getResources("db/location2"); + List exactFileLocationList = urlList(exactFileLocationEnumeration); + if (exactFileLocationList.size() != 0) { + return errorResult(testType, "wrong number of urls"); + } + return SUCCESS; + } catch (Exception e) { + e.printStackTrace(); + return errorResult(testType, "exception during resolution of resource"); + } + } + + private String assertCorrectDirectory() { + final String testType = "correct-directory"; + try { + Enumeration directoryEnumeration = this.getClass().getClassLoader().getResources("db/location"); + List directoryURLList = urlList(directoryEnumeration); + if (directoryURLList.size() != 1) { + return errorResult(testType, "wrong number of directory urls"); + } + + URL singleURL = directoryURLList.get(0); + + int separatorIndex = singleURL.getPath().lastIndexOf('!'); + String jarPath = singleURL.getPath().substring(0, separatorIndex); + String directoryName = singleURL.getPath().substring(separatorIndex + 2) + "/"; + + try (JarFile jarFile = new JarFile(Paths.get(new URI(jarPath)).toFile())) { + Enumeration entries = jarFile.entries(); + List entriesInDirectory = new ArrayList<>(); + while (entries.hasMoreElements()) { + JarEntry currentEntry = entries.nextElement(); + String entryName = currentEntry.getName(); + if (entryName.startsWith(directoryName) && !entryName.equals(directoryName)) { + entriesInDirectory.add(currentEntry); + } + } + + if (entriesInDirectory.size() != 1) { + return errorResult(testType, "wrong number of entries in jar directory"); + } + + try (InputStream is = jarFile.getInputStream(entriesInDirectory.get(0))) { + String fileContent = IOUtils.toString(is, StandardCharsets.UTF_8); + if (!fileContent.contains("CREATE TABLE")) { + return errorResult(testType, "wrong file content"); + } + return SUCCESS; + } + } + + + } catch (Exception e) { + e.printStackTrace(); + return errorResult(testType, "exception during resolution of resource"); + } + } + + private String assertTopLevelDirectory() { + final String testType = "top-level-directory"; + try { + Enumeration directoryEnumeration = this.getClass().getClassLoader().getResources("assets"); + List directoryURLList = urlList(directoryEnumeration); + if (directoryURLList.size() != 1) { + return errorResult(testType, "wrong number of directory urls"); + } + + return SUCCESS; + } catch (Exception e) { + e.printStackTrace(); + return errorResult(testType, "exception during resolution of resource"); + } + } + + private List urlList(Enumeration enumeration) { + if (enumeration == null) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + while (enumeration.hasMoreElements()) { + result.add(enumeration.nextElement()); + } + return result; + } + + private String errorResult(String testType, String message) { + return testType + " / " + message; + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/HelloResource.java b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/HelloResource.java new file mode 100644 index 0000000000000..c21e5305ea793 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/HelloResource.java @@ -0,0 +1,74 @@ +package org.acme; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@Path("/hello") +public class HelloResource { + + @ConfigProperty(name = "greeting") + String greeting; + + @ConfigProperty(name = "quarkus.application.version") + String applicationVersion; + + @ConfigProperty(name = "quarkus.application.name") + String applicationName; + + @ConfigProperty(name = "other.greeting", defaultValue = "other") + String otherGreeting; + + @ConfigProperty(name = "quarkus.profile") + String profile; + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "hello"; + } + + @GET + @Path("/greeting") + @Produces(MediaType.TEXT_PLAIN) + public String greeting() { + return greeting; + } + + @GET + @Path("/package") + @Produces(MediaType.TEXT_PLAIN) + public String pkg() { + return Blah.class.getPackage().getName(); + } + + @GET + @Path("/nameAndVersion") + @Produces(MediaType.TEXT_PLAIN) + public String nameAndVersion() { + return applicationName + "/" + applicationVersion; + } + + @GET + @Path("/otherGreeting") + @Produces(MediaType.TEXT_PLAIN) + public String otherGreeting() { + return otherGreeting; + } + + @GET + @Path("/profile") + @Produces(MediaType.TEXT_PLAIN) + public String profile() { + return profile; + } + + + public static class Blah { + + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/MyApplication.java b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/MyApplication.java new file mode 100644 index 0000000000000..a6d66f8b9eda2 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/MyApplication.java @@ -0,0 +1,9 @@ +package org.acme; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationPath("/app") +public class MyApplication extends Application { + +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/ProtectionDomain.java b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/ProtectionDomain.java new file mode 100644 index 0000000000000..36cfbe3d82e5e --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/java/org/acme/ProtectionDomain.java @@ -0,0 +1,77 @@ +package org.acme; + +import org.apache.commons.io.IOUtils; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.function.Supplier; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; + +@Path("/protectionDomain") +public class ProtectionDomain { + + private static final String SUCCESS = "success"; + + @GET + public String useProtectionDomain() { + return runAssertions( + () -> assertReadManifestFromJar() + ); + } + + private String runAssertions(Supplier... assertions) { + String result; + for (Supplier assertion : assertions) { + result = assertion.get(); + if (!SUCCESS.equals(result)) { + return result; + } + } + return SUCCESS; + } + + private String assertReadManifestFromJar() { + final String testType = "manifest-from-jar"; + try { + URL location = org.apache.commons.io.Charsets.class.getProtectionDomain().getCodeSource().getLocation(); + if (location == null) { + return errorResult(testType, "location should not be null"); + } + + try (InputStream inputStream = location.openStream()) { + try (JarInputStream jarInputStream = new JarInputStream(inputStream)) { + Manifest manifest = jarInputStream.getManifest(); + if (manifest == null) { + return errorResult(testType, "manifest should not be null"); + } + String implementationVersion = manifest.getMainAttributes().getValue("Implementation-Version"); + if (implementationVersion == null) { + return errorResult(testType, "implementation-version should not be null"); + } + } + } + return SUCCESS; + } catch (Exception e) { + e.printStackTrace(); + return errorResult(testType, "exception during resolution of resource"); + } + } + + private String errorResult(String testType, String message) { + return testType + " / " + message; + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/META-INF/resources/index.html b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/META-INF/resources/index.html new file mode 100644 index 0000000000000..c09bb5c96b869 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/META-INF/resources/index.html @@ -0,0 +1,156 @@ + + + + + acme - 1.0-SNAPSHOT + + + + + + +
+
+

Congratulations, you have created a new Quarkus application.

+ +

Why do you see this?

+ +

This page is served by Quarkus. The source is in + src/main/resources/META-INF/resources/index.html.

+ +

What can I do from here?

+ +

If not already done, run the application in dev mode using: mvn compile quarkus:dev. +

+
    +
  • Add REST resources, Servlets, functions and other services in src/main/java.
  • +
  • Your static assets are located in src/main/resources/META-INF/resources.
  • +
  • Configure your application in src/main/resources/application.properties. +
  • +
+ +

Do you like Quarkus?

+

Go give it a star on GitHub.

+ +

How do I get rid of this page?

+

Just delete the src/main/resources/META-INF/resources/index.html file.

+
+
+
+

Application

+
    +
  • GroupId: org.acme
  • +
  • ArtifactId: acme
  • +
  • Version: 1.0-SNAPSHOT
  • +
  • Quarkus Version: 999-SNAPSHOT
  • +
+
+
+

Next steps

+ +
+
+
+ + + + \ No newline at end of file diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/application.properties b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/application.properties new file mode 100644 index 0000000000000..4afcfeef83dca --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/application.properties @@ -0,0 +1,9 @@ +# Configuration file +key = value +greeting=bonjour +quarkus.log.level=INFO +quarkus.log.file.enable=false +quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n +quarkus.log.file.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n +quarkus.log.category."io.quarkus".level=INFO +quarkus.log.category."io.quarkus.deployment.dev".level=DEBUG diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/assets/test.txt b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/assets/test.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/db/location/test.sql b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/db/location/test.sql new file mode 100644 index 0000000000000..cddc725179c67 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/main/resources/db/location/test.sql @@ -0,0 +1,7 @@ +CREATE TABLE TEST_SCHEMA.quarkus_table2 +( + id INT, + name VARCHAR(20) +); +INSERT INTO TEST_SCHEMA.quarkus_table2(id, name) +VALUES (1, '1.0.1 QUARKED'); diff --git a/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/test/java/org/acme/HelloResourceTest.java b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/test/java/org/acme/HelloResourceTest.java new file mode 100644 index 0000000000000..c2f29e2c9f711 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/classic-with-log/src/test/java/org/acme/HelloResourceTest.java @@ -0,0 +1,21 @@ +package org.acme; + +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Test; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +@QuarkusTest +public class HelloResourceTest { + + @Test + public void testHelloEndpoint() { + given() + .when().get("/app/hello") + .then() + .statusCode(200) + .body(is("hello")); + } + +}