The archive contains: + *
Using {@code @DataSourceDefinition} rather than {@code WEB-INF/glassfish-resources.xml} + * is intentional: in GlassFish Embedded (Arquillian), the {@code jdbc-resource} element from + * {@code glassfish-resources.xml} inside a WAR is not bound to JNDI before + * {@code ResourceValidator.validateJNDIRefs} runs, causing deployment to fail with + * {@code NameNotFoundException: shopservice not found}. Annotation-based registration + * happens earlier in the deployment pipeline and is visible to the validator. + * + *
The datasource connects directly to H2 in-memory (no OJP proxy) for the test phase. + * H2's own {@code JdbcDataSource} is used so no custom adapter class is needed. + * + *
The datasource is registered in the {@code java:app/} namespace so that + * {@code persistence-test.xml} can reference it as {@code java:app/jdbc/shopservice}. + * + *
This class is only included in the ShrinkWrap archive used by tests (see
+ * {@link DeploymentFactory}) and is never bundled into the production WAR.
+ */
+@DataSourceDefinition(
+ name = "java:app/jdbc/shopservice",
+ className = "org.openjproxy.jdbc.OjpDataSource",
+ url = "jdbc:ojp[localhost:1059]_h2:mem:shopdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=LEGACY",
+ user = "sa",
+ password = "")
+@ApplicationScoped
+public class TestDataSourceProducer {
+}
diff --git a/glassfish/shopservice/src/test/java/com/example/shopservice/resource/OrderResourceTest.java b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/OrderResourceTest.java
new file mode 100644
index 0000000..c31f626
--- /dev/null
+++ b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/OrderResourceTest.java
@@ -0,0 +1,104 @@
+package com.example.shopservice.resource;
+
+import com.example.shopservice.DeploymentFactory;
+import io.restassured.http.ContentType;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit5.ArquillianExtension;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.net.URL;
+import java.util.UUID;
+
+import static io.restassured.RestAssured.*;
+import static org.hamcrest.Matchers.*;
+
+@ExtendWith(ArquillianExtension.class)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class OrderResourceTest {
+
+ @Deployment(testable = false)
+ public static WebArchive createDeployment() {
+ return DeploymentFactory.createDeployment();
+ }
+
+ @ArquillianResource
+ private URL base;
+
+ private Long createUser() {
+ String unique = UUID.randomUUID().toString();
+ return given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"username\":\"orderuser_" + unique + "\","
+ + "\"email\":\"orderuser_" + unique + "@example.com\"}")
+ .when()
+ .post("users")
+ .then()
+ .extract().jsonPath().getLong("id");
+ }
+
+ @Test
+ @Order(1)
+ public void testCreateOrder() {
+ Long userId = createUser();
+
+ given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"user\":{\"id\":" + userId + "}}")
+ .when()
+ .post("orders")
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .body("user.id", equalTo(userId.intValue()));
+ }
+
+ @Test
+ @Order(2)
+ public void testGetOrder() {
+ Long userId = createUser();
+
+ Long orderId = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"user\":{\"id\":" + userId + "}}")
+ .when()
+ .post("orders")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .get("orders/" + orderId)
+ .then()
+ .statusCode(200)
+ .body("user.id", equalTo(userId.intValue()));
+ }
+
+ @Test
+ @Order(3)
+ public void testDeleteOrder() {
+ Long userId = createUser();
+
+ Long orderId = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"user\":{\"id\":" + userId + "}}")
+ .when()
+ .post("orders")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .delete("orders/" + orderId)
+ .then()
+ .statusCode(204);
+ }
+}
diff --git a/glassfish/shopservice/src/test/java/com/example/shopservice/resource/ProductResourceTest.java b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/ProductResourceTest.java
new file mode 100644
index 0000000..0ea3eb4
--- /dev/null
+++ b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/ProductResourceTest.java
@@ -0,0 +1,118 @@
+package com.example.shopservice.resource;
+
+import com.example.shopservice.DeploymentFactory;
+import io.restassured.http.ContentType;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit5.ArquillianExtension;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.math.BigDecimal;
+import java.net.URL;
+
+import static io.restassured.RestAssured.*;
+import static org.hamcrest.Matchers.*;
+
+@ExtendWith(ArquillianExtension.class)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class ProductResourceTest {
+
+ @Deployment(testable = false)
+ public static WebArchive createDeployment() {
+ return DeploymentFactory.createDeployment();
+ }
+
+ @ArquillianResource
+ private URL base;
+
+ @Test
+ @Order(1)
+ public void testCreateProduct() {
+ given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"name\":\"Widget\",\"price\":19.99}")
+ .when()
+ .post("products")
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .body("name", equalTo("Widget"))
+ .body("price", equalTo(19.99f));
+ }
+
+ @Test
+ @Order(2)
+ public void testGetProduct() {
+ Long id = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"name\":\"Gadget\",\"price\":10.50}")
+ .when()
+ .post("products")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .get("products/" + id)
+ .then()
+ .statusCode(200)
+ .body("name", equalTo("Gadget"))
+ .body("price", equalTo(10.50f));
+ }
+
+ @Test
+ @Order(3)
+ public void testUpdateProduct() {
+ Long id = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"name\":\"Thing\",\"price\":5.00}")
+ .when()
+ .post("products")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"name\":\"Thing Updated\",\"price\":7.50}")
+ .when()
+ .put("products/" + id)
+ .then()
+ .statusCode(200)
+ .body("name", equalTo("Thing Updated"))
+ .body("price", equalTo(7.50f));
+ }
+
+ @Test
+ @Order(4)
+ public void testDeleteProduct() {
+ Long id = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"name\":\"ToDelete\",\"price\":" + new BigDecimal("1.00") + "}")
+ .when()
+ .post("products")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .delete("products/" + id)
+ .then()
+ .statusCode(204);
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .get("products/" + id)
+ .then()
+ .statusCode(404);
+ }
+}
diff --git a/glassfish/shopservice/src/test/java/com/example/shopservice/resource/ReviewResourceTest.java b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/ReviewResourceTest.java
new file mode 100644
index 0000000..41e0d30
--- /dev/null
+++ b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/ReviewResourceTest.java
@@ -0,0 +1,129 @@
+package com.example.shopservice.resource;
+
+import com.example.shopservice.DeploymentFactory;
+import io.restassured.http.ContentType;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit5.ArquillianExtension;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.net.URL;
+import java.util.UUID;
+
+import static io.restassured.RestAssured.*;
+import static org.hamcrest.Matchers.*;
+
+@ExtendWith(ArquillianExtension.class)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class ReviewResourceTest {
+
+ @Deployment(testable = false)
+ public static WebArchive createDeployment() {
+ return DeploymentFactory.createDeployment();
+ }
+
+ @ArquillianResource
+ private URL base;
+
+ private Long createUser() {
+ String unique = UUID.randomUUID().toString();
+ return given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"username\":\"reviewuser_" + unique + "\","
+ + "\"email\":\"reviewuser_" + unique + "@example.com\"}")
+ .when()
+ .post("users")
+ .then()
+ .extract().jsonPath().getLong("id");
+ }
+
+ private Long createProduct() {
+ String unique = UUID.randomUUID().toString();
+ return given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"name\":\"reviewprod_" + unique + "\",\"price\":8.90}")
+ .when()
+ .post("products")
+ .then()
+ .extract().jsonPath().getLong("id");
+ }
+
+ @Test
+ @Order(1)
+ public void testCreateReview() {
+ Long userId = createUser();
+ Long productId = createProduct();
+
+ given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"user\":{\"id\":" + userId + "},"
+ + "\"product\":{\"id\":" + productId + "},"
+ + "\"rating\":5,\"comment\":\"Excellent!\"}")
+ .when()
+ .post("reviews")
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .body("user.id", equalTo(userId.intValue()))
+ .body("product.id", equalTo(productId.intValue()))
+ .body("rating", equalTo(5))
+ .body("comment", equalTo("Excellent!"));
+ }
+
+ @Test
+ @Order(2)
+ public void testGetReview() {
+ Long userId = createUser();
+ Long productId = createProduct();
+
+ Long reviewId = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"user\":{\"id\":" + userId + "},"
+ + "\"product\":{\"id\":" + productId + "},"
+ + "\"rating\":4,\"comment\":\"Good!\"}")
+ .when()
+ .post("reviews")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .get("reviews/" + reviewId)
+ .then()
+ .statusCode(200)
+ .body("rating", equalTo(4))
+ .body("comment", equalTo("Good!"));
+ }
+
+ @Test
+ @Order(3)
+ public void testDeleteReview() {
+ Long userId = createUser();
+ Long productId = createProduct();
+
+ Long reviewId = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"user\":{\"id\":" + userId + "},"
+ + "\"product\":{\"id\":" + productId + "},"
+ + "\"rating\":2,\"comment\":\"Not great.\"}")
+ .when()
+ .post("reviews")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .delete("reviews/" + reviewId)
+ .then()
+ .statusCode(204);
+ }
+}
diff --git a/glassfish/shopservice/src/test/java/com/example/shopservice/resource/UserResourceTest.java b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/UserResourceTest.java
new file mode 100644
index 0000000..0518043
--- /dev/null
+++ b/glassfish/shopservice/src/test/java/com/example/shopservice/resource/UserResourceTest.java
@@ -0,0 +1,118 @@
+package com.example.shopservice.resource;
+
+import com.example.shopservice.DeploymentFactory;
+import io.restassured.http.ContentType;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit5.ArquillianExtension;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.net.URL;
+
+import static io.restassured.RestAssured.*;
+import static org.hamcrest.Matchers.*;
+
+@ExtendWith(ArquillianExtension.class)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class UserResourceTest {
+
+ @Deployment(testable = false)
+ public static WebArchive createDeployment() {
+ return DeploymentFactory.createDeployment();
+ }
+
+ @ArquillianResource
+ private URL base;
+
+ @Test
+ @Order(1)
+ public void testCreateUser() {
+ given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"username\":\"alice\",\"email\":\"alice@example.com\",\"createdAt\":\"2024-01-15T10:30:00\"}")
+ .when()
+ .post("users")
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .body("username", equalTo("alice"))
+ .body("email", equalTo("alice@example.com"))
+ .body("createdAt", notNullValue());
+ }
+
+ @Test
+ @Order(2)
+ public void testGetUser() {
+ Long id = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"username\":\"bob\",\"email\":\"bob@example.com\",\"createdAt\":\"2024-01-16T14:20:00\"}")
+ .when()
+ .post("users")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .get("users/" + id)
+ .then()
+ .statusCode(200)
+ .body("username", equalTo("bob"))
+ .body("email", equalTo("bob@example.com"));
+ }
+
+ @Test
+ @Order(3)
+ public void testUpdateUser() {
+ Long id = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"username\":\"carol\",\"email\":\"carol@example.com\"}")
+ .when()
+ .post("users")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"username\":\"carol_updated\",\"email\":\"carol_updated@example.com\"}")
+ .when()
+ .put("users/" + id)
+ .then()
+ .statusCode(200)
+ .body("username", equalTo("carol_updated"))
+ .body("email", equalTo("carol_updated@example.com"));
+ }
+
+ @Test
+ @Order(4)
+ public void testDeleteUser() {
+ Long id = given()
+ .baseUri(base.toExternalForm())
+ .contentType(ContentType.JSON)
+ .body("{\"username\":\"dave\",\"email\":\"dave@example.com\"}")
+ .when()
+ .post("users")
+ .then()
+ .extract().jsonPath().getLong("id");
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .delete("users/" + id)
+ .then()
+ .statusCode(204);
+
+ given()
+ .baseUri(base.toExternalForm())
+ .when()
+ .get("users/" + id)
+ .then()
+ .statusCode(404);
+ }
+}
diff --git a/glassfish/shopservice/src/test/resources/META-INF/persistence-test.xml b/glassfish/shopservice/src/test/resources/META-INF/persistence-test.xml
new file mode 100644
index 0000000..f65eb92
--- /dev/null
+++ b/glassfish/shopservice/src/test/resources/META-INF/persistence-test.xml
@@ -0,0 +1,42 @@
+
+