diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/pom.xml index 7c00080373e7d..5e79b5015cd8a 100644 --- a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/pom.xml +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/pom.xml @@ -31,7 +31,27 @@ io.quarkus - quarkus-resteasy + quarkus-agroal + + + io.quarkus + quarkus-rest + + + io.quarkus + quarkus-rest-jackson + + + io.quarkus + quarkus-hibernate-orm + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-jdbc-postgresql io.quarkus diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/java/org/acme/Fruit.java b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/java/org/acme/Fruit.java new file mode 100644 index 0000000000000..72dd4c602d87e --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/java/org/acme/Fruit.java @@ -0,0 +1,50 @@ +package org.acme; + +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.QueryHint; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; + +@Entity +@Table(name = "known_fruits") +@NamedQuery(name = "Fruits.findAll", query = "SELECT f FROM Fruit f ORDER BY f.name", hints = @QueryHint(name = "org.hibernate.cacheable", value = "true")) +@Cacheable +public class Fruit { + + @Id + @SequenceGenerator(name = "fruitsSequence", sequenceName = "known_fruits_id_seq", allocationSize = 1, initialValue = 10) + @GeneratedValue(generator = "fruitsSequence") + private Integer id; + + @Column(length = 40, unique = true) + private String name; + + public Fruit() { + } + + public Fruit(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/java/org/acme/FruitResource.java b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/java/org/acme/FruitResource.java new file mode 100644 index 0000000000000..cd8f8914fbb5a --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/java/org/acme/FruitResource.java @@ -0,0 +1,124 @@ +package org.acme; + +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +import org.jboss.logging.Logger; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +@Path("fruits") +@ApplicationScoped +@Produces("application/json") +@Consumes("application/json") +public class FruitResource { + + private static final Logger LOGGER = Logger.getLogger(FruitResource.class.getName()); + + @Inject + EntityManager entityManager; + + @GET + public List get() { + return entityManager.createNamedQuery("Fruits.findAll", Fruit.class) + .getResultList(); + } + + @GET + @Path("{id}") + public Fruit getSingle(Integer id) { + Fruit entity = entityManager.find(Fruit.class, id); + if (entity == null) { + throw new WebApplicationException("Fruit with id of " + id + " does not exist.", 404); + } + return entity; + } + + @POST + @Transactional + public Response create(Fruit fruit) { + if (fruit.getId() != null) { + throw new WebApplicationException("Id was invalidly set on request.", 422); + } + + entityManager.persist(fruit); + return Response.ok(fruit).status(201).build(); + } + + @PUT + @Path("{id}") + @Transactional + public Fruit update(Integer id, Fruit fruit) { + if (fruit.getName() == null) { + throw new WebApplicationException("Fruit Name was not set on request.", 422); + } + + Fruit entity = entityManager.find(Fruit.class, id); + + if (entity == null) { + throw new WebApplicationException("Fruit with id of " + id + " does not exist.", 404); + } + + entity.setName(fruit.getName()); + + return entity; + } + + @DELETE + @Path("{id}") + @Transactional + public Response delete(Integer id) { + Fruit entity = entityManager.getReference(Fruit.class, id); + if (entity == null) { + throw new WebApplicationException("Fruit with id of " + id + " does not exist.", 404); + } + entityManager.remove(entity); + return Response.status(204).build(); + } + + @Provider + public static class ErrorMapper implements ExceptionMapper { + + @Inject + ObjectMapper objectMapper; + + @Override + public Response toResponse(Exception exception) { + LOGGER.error("Failed to handle request", exception); + + int code = 500; + if (exception instanceof WebApplicationException) { + code = ((WebApplicationException) exception).getResponse().getStatus(); + } + + ObjectNode exceptionJson = objectMapper.createObjectNode(); + exceptionJson.put("exceptionType", exception.getClass().getName()); + exceptionJson.put("code", code); + + if (exception.getMessage() != null) { + exceptionJson.put("error", exception.getMessage()); + } + + return Response.status(code) + .entity(exceptionJson) + .build(); + } + + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/resources/application.properties b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/resources/application.properties new file mode 100644 index 0000000000000..88e433c289c38 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/resources/application.properties @@ -0,0 +1,2 @@ +quarkus.hibernate-orm.log.sql=true +quarkus.hibernate-orm.sql-load-script=import.sql diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/resources/import.sql b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/resources/import.sql new file mode 100644 index 0000000000000..a64afab059f65 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/main/resources/import.sql @@ -0,0 +1,4 @@ +INSERT INTO known_fruits(id, name) VALUES (1, 'Cherry'); +INSERT INTO known_fruits(id, name) VALUES (2, 'Apple'); +INSERT INTO known_fruits(id, name) VALUES (3, 'Banana'); +ALTER SEQUENCE known_fruits_id_seq RESTART WITH 4; diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/FruitsEndpointIT.java b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/FruitsEndpointIT.java new file mode 100644 index 0000000000000..91b15288e129c --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/FruitsEndpointIT.java @@ -0,0 +1,10 @@ +package org.acme; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class FruitsEndpointIT extends FruitsEndpointTest { + + // Runs the same tests as the parent class + +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/FruitsEndpointTest.java b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/FruitsEndpointTest.java new file mode 100644 index 0000000000000..e3027672ffd67 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/FruitsEndpointTest.java @@ -0,0 +1,63 @@ +package org.acme; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.core.IsNot.not; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class FruitsEndpointTest { + + @Test + public void testListAllFruits() { + //List all, should have all 3 fruits the database has initially: + given() + .when().get("/fruits") + .then() + .statusCode(200) + .body( + containsString("Cherry"), + containsString("Apple"), + containsString("Banana")); + + //Delete the Cherry: + given() + .when().delete("/fruits/1") + .then() + .statusCode(204); + + //List all, cherry should be missing now: + given() + .when().get("/fruits") + .then() + .statusCode(200) + .body( + not(containsString("Cherry")), + containsString("Apple"), + containsString("Banana")); + + //Create the Pear: + given() + .when() + .body("{\"name\" : \"Pear\"}") + .contentType("application/json") + .post("/fruits") + .then() + .statusCode(201); + + //List all, cherry should be missing now: + given() + .when().get("/fruits") + .then() + .statusCode(200) + .body( + not(containsString("Cherry")), + containsString("Apple"), + containsString("Banana"), + containsString("Pear")); + } + +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/GreetingResourceTest.java b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/GreetingResourceTest.java index 2f0e3284d3d71..df95381a1ffe6 100644 --- a/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/GreetingResourceTest.java +++ b/integration-tests/maven/src/test/resources-filtered/projects/native-agent-integration/src/test/java/org/acme/GreetingResourceTest.java @@ -25,7 +25,6 @@ public void testUnknownName() given() .when().get("/hello/Bob") .then() - .statusCode(404) - .body(is("")); + .statusCode(404); } } \ No newline at end of file diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java index 3f7680375d4a6..d63eff417389e 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java @@ -1,6 +1,7 @@ package io.quarkus.test.junit; import static io.quarkus.test.junit.ArtifactTypeUtil.isContainer; +import static io.quarkus.test.junit.ArtifactTypeUtil.isJar; import static io.quarkus.test.junit.IntegrationTestUtil.activateLogging; import static io.quarkus.test.junit.IntegrationTestUtil.determineBuildOutputDirectory; import static io.quarkus.test.junit.IntegrationTestUtil.determineTestProfileAndProperties; @@ -194,7 +195,10 @@ private QuarkusTestExtensionState doProcessStart(Properties quarkusArtifactPrope String artifactType = getArtifactType(quarkusArtifactProperties); - boolean isDockerLaunch = isContainer(artifactType); + Config config = LauncherUtil.installAndGetSomeConfig(); + String testProfile = TestConfigUtil.integrationTestProfile(config); + boolean isDockerLaunch = isContainer(artifactType) + || (isJar(artifactType) && "test-with-native-agent".equals(testProfile)); ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult = handleDevServices(context, isDockerLaunch); @@ -272,10 +276,8 @@ public void close() throws Throwable { if ((testHost != null) && !testHost.isEmpty()) { launcher = new TestHostLauncher(); } else { - Config config = LauncherUtil.installAndGetSomeConfig(); Duration waitDuration = TestConfigUtil.waitTimeValue(config); String target = TestConfigUtil.runTarget(config); - String testProfile = TestConfigUtil.integrationTestProfile(config); // try to execute a run command published by an extension if it exists. We do this so that extensions that have a custom run don't have to create any special artifact type launcher = RunCommandLauncher.tryLauncher(devServicesLaunchResult.getCuratedApplication().getQuarkusBootstrap(), target, waitDuration);