Repository: eclipse/microprofile-lra
Pull request #267 (2020-01-16 11:23:42)

issue6 Timeout tests
#6 

The issue called for 3 different tests. I implemented the first one TckTests#timeLimitWithPreConditionFailed
The second test is very similar to TckTests#timeLimit so I have not added a one for that.
The third test that was asked for was to verify that the time limit is respected after a system crash. But we already have a test for that (see TckRecoveryTests#testCancelWhenParticipantIsUnavailable).


Patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraResource.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraResource.java
index cab64e2..11a22b9 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraResource.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraResource.java
@@ -31,6 +31,7 @@ import org.eclipse.microprofile.lra.annotation.Status;
 import org.eclipse.microprofile.lra.annotation.ParticipantStatus;
 import org.eclipse.microprofile.lra.tck.service.LRAMetricService;
 import org.eclipse.microprofile.lra.tck.service.LRAMetricType;
+import org.eclipse.microprofile.lra.tck.service.LRATestService;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
@@ -69,10 +70,12 @@ public class LraResource {
     public static final String LRA_RESOURCE_PATH = "lraresource";
     public static final String TRANSACTIONAL_WORK_PATH = "work";
     public static final String ACCEPT_WORK = "acceptWork";
-    private static final Logger LOGGER = Logger.getLogger(LraResource.class.getName());
-
+    public static final String TIME_LIMIT = "/timeLimit";
+    public static final String TIME_LIMIT_HALF_SEC = "/timeLimit2";
     static final String MANDATORY_LRA_RESOURCE_PATH = "/mandatory";
 
+    private static final Logger LOGGER = Logger.getLogger(LraResource.class.getName());
+
     private static final String MISSING_LRA_DATA = "Missing LRA data";
 
     @Context
@@ -84,6 +87,8 @@ public class LraResource {
     @Inject
     private LRAMetricService lraMetricService;
 
+    @Inject
+    LRATestService lraTestService;
     /**
      * Performing a GET on the participant URL will return the current status of the
      * participant {@link ParticipantStatus}, or 410 if the participant does no longer know about this LRA.
@@ -394,7 +399,7 @@ public class LraResource {
     }
 
     @GET
-    @Path("/timeLimit")
+    @Path(TIME_LIMIT)
     @Produces(MediaType.APPLICATION_JSON)
     @LRA(value = LRA.Type.REQUIRED, timeLimit = 100, timeUnit = ChronoUnit.MILLIS)
     public Response timeLimit(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId) {
@@ -410,6 +415,34 @@ public class LraResource {
         return Response.status(Response.Status.OK).entity(lraId.toASCIIString()).build();
     }
 
+    /**
+     * @see org.eclipse.microprofile.lra.tck.TckTests#timeLimitWithPreConditionFailed
+     */
+    @GET
+    @Path(TIME_LIMIT_HALF_SEC)
+    @Produces(MediaType.APPLICATION_JSON)
+    @LRA(value = LRA.Type.REQUIRED, timeLimit = 500, timeUnit = ChronoUnit.MILLIS)
+    public Response timeLimitTest2(@HeaderParam(LRA_HTTP_CONTEXT_HEADER) URI lraId) {
+        assertHeaderPresent(lraId, LRA_HTTP_CONTEXT_HEADER);
+
+        activityStore.add(new Activity(lraId));
+
+        try {
+            Thread.sleep(1000); // sleep for longer than specified in the timeLimit annotation attribute
+            // force the implementation to notice that the LRA should have timed out
+            lraTestService.waitForCallbacks(lraId);
+            // the next request should fail with a 412 code since the LRA should no longer be active
+            restPutInvocation(lraId, MANDATORY_LRA_RESOURCE_PATH, "");
+        } catch (WebApplicationException wae) {
+            return Response.status(wae.getResponse().getStatus()).build();
+        } catch (InterruptedException e) {
+            LOGGER.log(Level.FINE, "timeLimitTest2: Interrupted because time limit elapsed", e);
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        }
+
+        return Response.status(Response.Status.OK).entity(lraId.toASCIIString()).build();
+    }
+
     /**
      * Performing a PUT on "participant URL"/compensate will cause the participant to compensate
      * the work that was done within the scope of the transaction.


Test patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java
index 1768707..44a7df3 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckTests.java
@@ -23,6 +23,8 @@ import static org.eclipse.microprofile.lra.annotation.ws.rs.LRA.LRA_HTTP_CONTEXT
 import static org.eclipse.microprofile.lra.tck.participant.api.AfterLRAListener.AFTER_LRA_LISTENER_WORK;
 import static org.eclipse.microprofile.lra.tck.participant.api.LraResource.ACCEPT_WORK;
 import static org.eclipse.microprofile.lra.tck.participant.api.LraResource.LRA_RESOURCE_PATH;
+import static org.eclipse.microprofile.lra.tck.participant.api.LraResource.TIME_LIMIT;
+import static org.eclipse.microprofile.lra.tck.participant.api.LraResource.TIME_LIMIT_HALF_SEC;
 import static org.eclipse.microprofile.lra.tck.participant.api.LraResource.TRANSACTIONAL_WORK_PATH;
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.JOIN_WITH_EXISTING_LRA_PATH;
 import static org.eclipse.microprofile.lra.tck.participant.api.ParticipatingTckResource.JOIN_WITH_EXISTING_LRA_PATH2;
@@ -314,7 +316,7 @@ public class TckTests extends TckTestBase {
 
     @Test
     public void timeLimit() {
-        WebTarget resourcePath = tckSuiteTarget.path(LRA_RESOURCE_PATH).path("timeLimit");
+        WebTarget resourcePath = tckSuiteTarget.path(LRA_RESOURCE_PATH).path(TIME_LIMIT);
         Response response = resourcePath
                 .request()
                 .get();
@@ -344,6 +346,31 @@ public class TckTests extends TckTestBase {
                 1, lraMetricService.getMetric(LRAMetricType.Compensated, lraId, LraResource.class.getName()));
     }
 
+    /**
+     * Service A - Timeout 500 ms
+     * Service B - Type.MANDATORY
+     *
+     * Service A calls Service B after it has waited 1 sec.
+     * Service A returns http Status from the call to Service B.
+     *
+     * test calls A and verifies if return is status 412 (precondition failed) since LRA
+     * is not active when Service B endpoint is called.
+     */
+    @Test
+    public void timeLimitWithPreConditionFailed() {
+        WebTarget resourcePath = tckSuiteTarget.path(LRA_RESOURCE_PATH).path(TIME_LIMIT_HALF_SEC);
+        Response response = resourcePath
+                .request()
+                .get();
+
+        // verify that a 412 response code was generated
+        assertEquals("Expected 412 response",
+                Response.Status.PRECONDITION_FAILED.getStatusCode(),
+                response.getStatus());
+
+        response.close();
+    }
+
     @Test
     public void acceptCloseTest() throws WebApplicationException, InterruptedException {
         joinAndEnd(true, LRA_RESOURCE_PATH, ACCEPT_WORK);