Repository: eclipse/microprofile-lra
Pull request #99 (2019-02-18 09:03:17)

issue84: canceling LRA when exception is thrown from @LRA annotated method
fixes https://github.com/eclipse/microprofile-lra/issues/84

clarification of the rules for ending the `@LRA` annotation when using `cancelOn`/`cancelOnFamily`. adding tck tests to verify the behaviour

mmusgrov: How does this test differ from the existing cancelOn and cancelOnFamily TCK tests?
ochaloup:  @mmusgrov in functionality it does not differ. Those two tests which were part of the TckTests are rip off and moved to the separate test class that gathers all of the cancelOn cases. The new tck class is then enriched with new scenarios.
It would be possible to put all the tests (aka. adding the new ones) to the `TckTests` class but I think it's already quite huge and transforming it for having multiple test classes each with separate responsibility is a good move. Especially I think we need to add more tck tests in general and having all of them in one test class does not seem to me a good practice.
tomjenkinson: I agree. A single monolithic test suite is hard to read and maintain. Unless there is a precedent from other specs?
ochaloup: @xstefank @mmusgrov @rdebusscher I updated the javadoc with clarification about `end` attribute as discussed on the meeting. Please, let me know if something is wrong or could be done better. Thanks.

Patch:
diff --git a/README.adoc b/README.adoc
index ceb8651..a72e040 100644
--- a/README.adoc
+++ b/README.adoc
@@ -16,34 +16,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-image:https://badges.gitter.im/eclipse/microprofile-lra.svg[link="https://gitter.im/eclipse/microprofile-lra?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
 
 # Long Running Actions for MicroProfile
 
-'''
-## How to contribute
-
-Do you want to contribute to this project? Here is what you can do:
-
-* Fork the repository, make changes, then do a pull request.
-** Remember to https://help.github.com/articles/signing-commits/[sign your commits]
-** Make sure you have signed the https://www.eclipse.org/legal/ECA.php[Eclipse Contributor Agreement]
-* https://github.com/eclipse/microprofile-lra/issues[Create or fix an issue].
-* https://gitter.im/eclipse/microprofile-lra[Join us on Gitter to discuss this project].
-* Join our https://calendar.google.com/calendar/embed?src=gbnbc373ga40n0tvbl88nkc3r4%40group.calendar.google.com[weekly meeting] on Mondays at https://www.timeanddate.com/time/map/[10h00 GMT]. 
-** https://docs.google.com/document/d/1HBPiXpsXcQp9T8JeoT-IDs-EblZX1SxuTV5qjUPzwrM/edit[Minutes and Agenda].
-** https://eclipse.zoom.us/j/949859967[Meeting room].
-* Join the discussions on the https://groups.google.com/forum/#!forum/microprofile[MicroProfile Google Group]
-* https://microprofile.io/blog/[Contribute a blog post].
-
-'''
-
 ## Status
 
 MicroProfile LRA proposal in progress
 
 == Introduction
 
+image:https://badges.gitter.im/eclipse/microprofile-lra.svg[link="https://gitter.im/eclipse/microprofile-lra?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
+
 The specification introduces APIs for services to coordinate activities.
 
 The main thrust of the proposal introduces an API for loosely coupled
diff --git a/api/src/main/java/org/eclipse/microprofile/lra/annotation/LRA.java b/api/src/main/java/org/eclipse/microprofile/lra/annotation/LRA.java
index ff9f69b..0626411 100644
--- a/api/src/main/java/org/eclipse/microprofile/lra/annotation/LRA.java
+++ b/api/src/main/java/org/eclipse/microprofile/lra/annotation/LRA.java
@@ -20,7 +20,11 @@
 
 package org.eclipse.microprofile.lra.annotation;
 
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.core.Response;
+
+import org.eclipse.microprofile.lra.client.LRAClient;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
@@ -29,41 +33,52 @@ import java.lang.annotation.Target;
 import java.time.temporal.ChronoUnit;
 
 /**
+ * <p>
  * An annotation for controlling the lifecycle of Long Running Actions (LRAs).
  *
- * The annotation SHOULD be applied to JAX-RS annotated methods otherwise
- * it MAY have no effect. The annotation determines whether or not the annotated
+ * <p>
+ * The annotation <b>SHOULD</b> be applied to JAX-RS annotated methods otherwise
+ * it <b>MAY</b> have no effect. The annotation determines whether or not the annotated
  * method will run in the context of an LRA and controls whether or not:
+ * </p>
  *
- * - any incomming context should be suspended and if so if a new one should be started.
- * - to start an new LRA.
- * - to end any LRA context when the method ends.
- * - to throw an exception if there should be an LRA present on method entry.
- * - to throw an exception if the method returns particular HTTP status codes.
+ * <ul>
+ *   <li>any incoming context should be suspended and if so if a new one should be started</li>
+ *   <li>to start a new LRA</li>
+ *   <li>to end any LRA context when the method ends</li>
+ *   <li>to throw an exception if there should be an LRA context present on method entry</li>
+ *   <li>to cancel LRA context when the method returns particular HTTP status codes</li>
+ * </ul>
  *
+ * <p>
  * Newly created LRAs are uniquely identified and the id is referred to as the
  * LRA context. The context is passed around using a JAX-RS request/response header
  * called {@link org.eclipse.microprofile.lra.client.LRAClient#LRA_HTTP_HEADER}.
  * The implementation (of the LRA specification) is expected to manage this context
  * and the application developer is expected to declaratively control the creation,
- * propagation and destruction of LRAs using the @LRA annotation. When a JAX-RS bean
+ * propagation and destruction of LRAs using the {@link LRA} annotation. When a JAX-RS bean
  * method is invoked in the context of an LRA any JAX-RS client requests that it
  * performs will carry the same header so that the receiving resource knows that it
  * is inside an LRA context.
+ * </p>
  *
+ * <p>
  * If an LRA is propagated to a resource that is not annotated with any
  * particular LRA behaviour then the LRA will be suspended. But if this resource
  * then performs an outgoing JAX-RS request then the suspended LRA must be propagated
- * on this second outgoing request. For example, suppose resource A starts an LRA
- * and then performs a JAX-RS request to resource B which does not contain any LRA
- * annotations. If resource B then performs a JAX-RS request to a third service, C say,
- * which does contain LRA annotations then the LRA context started at A must be propagated
- * to C (for example if C uses LRAClient or annotations to join the LRA, then C must be
- * enlisted in the LRA that was started at A).
+ * on this second outgoing request. For example, suppose resource <code>A</code> starts an LRA
+ * and then performs a JAX-RS request to resource <code>B</code> which does not contain any LRA
+ * annotations. If resource <code>B</code> then performs a JAX-RS request to a third service, <code>C</code> say,
+ * which does contain LRA annotations then the LRA context started at <code>A</code> must be propagated
+ * to <code>C</code> (for example if <code>C</code> uses {@link LRAClient} or annotations to join the LRA,
+ * then <code>C</code> must be enlisted in the LRA that was started at <code>A</code>).
+ * </p>
  *
+ * <p>
  * Resource methods can access the LRA context id, if required, by injecting it via
- * the JAX-RS @HeaderParam annotation. This may be useful, for example, for
+ * the JAX-RS {@link HeaderParam} annotation. This may be useful, for example, for
  * associating business work with an LRA.
+ * </p>
  */
 @Inherited
 @Retention(value = RetentionPolicy.RUNTIME)
@@ -71,14 +86,17 @@ import java.time.temporal.ChronoUnit;
 public @interface LRA {
 
     /**
+     * <p>
      * The Type element of the LRA annotation indicates whether a bean method
      * is to be executed within the context of a LRA.
      *
+     * <p>
      * If the method is to run in the context of an LRA and the annotated class
      * also contains methods annotated with {@link Compensate}/{@link Compensate}
      * then the bean will enlisted with the LRA. Enlisting with an LRA means that
      * the bean will be notified when the current LRA is later cancelled/closed.
      *
+     * <p>
      * The element values
      * {@link LRA.Type#REQUIRED} and {@link LRA.Type#REQUIRES_NEW} can start
      * new LRAs which by default will be closed when the annotated method
@@ -87,13 +105,15 @@ public @interface LRA {
      * when the method completes. To force the LRA to cancel instead of complete
      * use the {@link LRA#cancelOnFamily()} or {@link LRA#cancelOn()} attributes.
      *
+     * <p>
      * If an LRA was already present before the annotated method is invoked then it
      * will remain active after the method completes. This default behaviour can be
      * overridden using the {@link LRA#end()} attibute which will force
      * the LRA to complete or cancel (if the {@link LRA#cancelOnFamily()} or
      * {@link LRA#cancelOn()} attributes are present).
      *
-     * When an LRA is present its identifer MUST be made available to
+     * <p>
+     * When an LRA is present its identifer <b>MUST</b> be made available to
      * the business logic in the JAX-RS request and response header
      * {@link org.eclipse.microprofile.lra.client.LRAClient#LRA_HTTP_HEADER}
      *
@@ -103,65 +123,87 @@ public @interface LRA {
 
     enum Type {
         /**
+         * <p>
          * If called outside a LRA context a new LRA will be created for the
          * the duration of the method call and when the call completes it will
          * be closed.
+         * </p>
          *
+         * <p>
          * If called inside a LRA context the invoked method will run with the
          * same context and the context will remain active after the method
          * completes.
+         * </p>
          */
         REQUIRED,
 
         /**
+         * <p>
          * If called outside a LRA context a new LRA will be created for the
          * the duration of the method call and when the call completes it will
          * be terminated (closed or cancelled).
+         * </p>
          *
+         * <p>
          * If called inside a LRA context it will be suspended and a new LRA
          * context will be created for the duration of the call. When the method
          * finishes this new LRA will be terminated (closed or cancelled) and
          * the original context will be resumed.
+         * </p>
          *
+         * <p>
          * But note that if there was already a context active before the method
          * was invoked and the {@link LRA#end} attribute is set to false
          * then the new LRA is left active. In this case the original LRA will
          * remain suspended.
+         * </p>
          */
         REQUIRES_NEW,
 
         /**
-         *  If called outside a transaction context, the method call will return
-         *  with a 412 Precondition Failed HTTP status code
+         * <p>
+         * If called outside a transaction context, the method call will return
+         * with a <code>412 Precondition Failed</code> HTTP status code
+         * </p>
          *
-         *  If called inside a transaction context the bean method execution will
-         *  then continue within that context.
+         * <p>
+         * If called inside a transaction context the bean method execution will
+         * then continue within that context.
+         * </p>
          */
         MANDATORY,
 
         /**
+         *  <p>
          *  If called outside a LRA context the bean method execution
          *  must then continue outside a LRA context.
+         *  </p>
          *
+         *  <p>
          *  If called inside a LRA context the managed bean method execution
          *  must then continue inside this LRA context.
+         *  </p>
          */
         SUPPORTS,
 
         /**
-         *  The bean method is executed without a LRA context. If a context is
-         *  present on entry then it is suspended and then resumed after the
-         *  execution has completed.
+         * The bean method is executed without a LRA context. If a context is
+         * present on entry then it is suspended and then resumed after the
+         * execution has completed.
          */
         NOT_SUPPORTED,
 
         /**
-         *  If called outside a LRA context the managed bean method execution
-         *  must then continue outside a LRA context.
+         * <p>
+         * If called outside a LRA context the managed bean method execution
+         * must then continue outside a LRA context.
+         * </p>
          *
-         *  If called inside a LRA context the method is not executed and a
-         *  <code>412 Precondition Failed</code> HTTP status code is returned
-         *  to the caller.
+         * <p>
+         * If called inside a LRA context the method is not executed and a
+         * <code>412 Precondition Failed</code> HTTP status code is returned
+         * to the caller.
+         * </p>
          */
         NEVER
     }
@@ -184,9 +226,19 @@ public @interface LRA {
     ChronoUnit timeUnit() default ChronoUnit.SECONDS;
 
     /**
+     * <p>
      * Normally if an LRA is present when a bean method is executed it will not
      * be ended when the method returns. To override this behaviour and force LRA
-     * termination on exit use the end element
+     * termination on exit use the end element.
+     * </p>
+     *
+     * <p>
+     * If the <code>end</code> value is set to <code>false</code>
+     * while the annotated method returns the {@link Response} status code
+     * with the meaning the LRA to be cancelled (see {@link #cancelOn()} and {@link #cancelOnFamily()})
+     * then this error state has precedence over the <code>end</code> attribute.
+     * It means the LRA will be cancelled despite the end was set to <code>false</code>.
+     * </p>
      *
      * @return true if an LRA that was present before method execution will be
      * terminated when the bean method finishes.
@@ -194,20 +246,30 @@ public @interface LRA {
     boolean end() default true;
 
     /**
+     * <p>
      * The cancelOnFamily element can be set to indicate which families of
-     * HTTP response codes will cause the current LRA to cancel. By default client
-     * errors (4xx codes) and server errors (5xx codes) will result in
-     * cancellation of the LRA.
+     * HTTP response codes will cause the current LRA to cancel.
+     * This expects the annotated method is the JAX-RS endpoint where the {@link Response}
+     * with the status code could be returned.
+     * </p>
+     *
+     * <p>
+     * By default client errors (<code>4xx codes</code>) and server errors (<code>5xx codes</code>)
+     * will result in cancellation of the LRA.
+     * </p>
      *
      * @return the {@link Response.Status.Family} families that will cause
      * cancellation of the LRA
      */
     Response.Status.Family[] cancelOnFamily() default {
+        Response.Status.Family.CLIENT_ERROR, Response.Status.Family.SERVER_ERROR
     };
 
     /**
      * The cancelOn element can be set to indicate which  HTTP response
-     * codes will cause the current LRA to cancel
+     * codes will cause the current LRA to cancel.
+     * This expects the annotated method is the JAX-RS endpoint where the {@link Response}
+     * with the status code could be returned.
      *
      * @return the {@link Response.Status} HTTP status codes that will cause
      * cancellation of the LRA
diff --git a/spec/src/main/asciidoc/microprofile-lra-spec.adoc b/spec/src/main/asciidoc/microprofile-lra-spec.adoc
index efd044f..9615d9f 100644
--- a/spec/src/main/asciidoc/microprofile-lra-spec.adoc
+++ b/spec/src/main/asciidoc/microprofile-lra-spec.adoc
@@ -289,9 +289,8 @@ annotated with `@Compensate` and `@Complete` then these methods will be associat
 the active LRA. They will be invoked when the LRA is subsequently cancelled or closed.
 If the participant successfully compensates or completes then it may forget about the LRA.
 Otherwise it should remember that it is still associated with the LRA and it MUST report
-the status of the association using values in the
-https://github.com/eclipse/microprofile-lra/tree/master/api/src/main/java/org/eclipse/microprofile/lra/annotation/ParticipantStatus.java[`ParticipantStatus`]
-enum according to the participant state model defined earlier.
+the status of the association using values in the `ParticipantStatus` enum according to
+the participant state model defined earlier.
 It can report the status directly from the `@Compensate` or `@Complete` methods if they
 are idempotent, otherwise it MUST provide a method annotated with `@Status`.
 
@@ -406,20 +405,37 @@ attributes of the LRA:
 new LRAs which by default will be closed when the annotated method
 completes. This default behaviour can be overridden using the
 `LRA#end()` attribute which will leave the new LRA active
-when the method completes. To force the LRA to cancel instead of complete
+when the method completes.
+
+In normal circumstances the LRA is closed by the end of the method.
+To force the LRA to cancel instead to close
 use the `LRA#cancelOnFamily()` or `LRA#cancelOn()` attributes.
+These attributes defines families or/and sets of status codes
+which when returned as the
+https://javaee.github.io/javaee-spec/javadocs/javax/ws/rs/core/Response.html#status-int-[Response status code]
+cause the LRA to be cancelled.
+
+Bear in mind that the LRA is expected to be used at JAX-RS
+which expects the `Response` being the method return type.
+The specification does not discuss what happens when
+an uncaught exception is thrown from the `@LRA` annotated method.
+It's up to the framework to transform the thrown exception
+to the JAX-RS `Response` error status code.
+It's a usual practice the `RuntimeException` to be transformed
+to the `5xx` `Response` status code.
 
 If an LRA was already present before the annotated method is invoked then it
-will remain active after the method completes. This default behaviour can be
-overridden using the `LRA#end()` attribute which will force
-the LRA to complete or cancel.
+will remain active after the method completes. This default behaviour
+can be overridden using the `LRA#end()` attribute which will force
+the LRA to be finished. If it is closed or cancelled depends on the Response status return code.
 
 When an LRA is present its identifier MUST be made available to
 the business logic via request and response headers as described earlier
 (using a header name specified in the Java constant `LRA_HTTP_HEADER`).
 
 The following is a simple example of how to start an LRA and how to receive
-a notification when the LRA later cancelled or closed:
+a notification when the LRA is later cancelled (`@Compensate` is invoked)
+or closed (`@Complete` is invoked):
 
 [source,java]
 ----
@@ -488,7 +504,7 @@ by reading the request and response headers.
 
 The next example demonstrates how to start an LRA in one method and close
 it in a different method using the `end` attribute.
-It also shows how to automatically cancel the LRA if the business method
+It also shows how to configure the LRA to be automatically cancelled if the business method
 returns the particular HTTP status codes identified in the `cancelOn` and
 `cancelOnFamily` attributes:
 
diff --git a/tck/running_the_tck.asciidoc b/tck/running_the_tck.asciidoc
index 91d040a..9cdf42d 100644
--- a/tck/running_the_tck.asciidoc
+++ b/tck/running_the_tck.asciidoc
@@ -23,7 +23,8 @@ The LRA TCK suite can be parametrized by following properties, handled in the su
 
 `lra.tck.base.url`::
   The URL where the TCK suite deployment is exposed at. The TCK suite will construct path based on this URL.
-  The default base URL is `http://localhost:8180`.
+  The default base URL is `http://localhost:8180`. This property needs to be provided for the container,
+  and for the tests themselves (failsafe/surefire) too.
 `lra.tck.timeout.factor`::
   Timeout factor adjust timeout values used in the TCK suite. The default value is `1.0`.
   When set bigger than `1.0` then timeout value will be bigger and waiting time is longer.
@@ -41,6 +42,8 @@ The LRA TCK suite can be parametrized by following properties, handled in the su
 * implementation provides one implementation of `org.eclipse.microprofile.lra.client.LRAClient` as it's injected by TCK suite
 * implementation has to provide one implementation of `org.eclipse.microprofile.lra.tck.spi.ManagementSPI`. This is an interface
   with definition of util methods used by the TCK suite for its run.
+* JAX-RS `ClientBuilder` is used to run REST calls from tests to tested application. Provide the implementation of the
+  JAX-RS `ClientBuilder` on the test class path.
 
 === Setting-up pom.xml dependencies and running the tests
 
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/LRAInfo.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/LRAInfo.java
index c511ef8..1a9d901 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/LRAInfo.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/LRAInfo.java
@@ -22,42 +22,42 @@ package org.eclipse.microprofile.lra.tck;
 
 /**
  * Data object carrying information about an instance
- * of LRA (specified by LRA id) and it's status.
+ * of LRA (specified by lra id) and it's status.
  */
 public interface LRAInfo {
 
     /**
-     * @return  LRA id that LRA instance is identified by
+     * @return  lra id that lra instance is identified by
      */
     String getLraId();
 
     /**
-     * @return  LRA client id
+     * @return  lra client id
      */
     String getClientId();
 
     /**
-     * @return  true if LRA was successfully closed, false otherwise
+     * @return  true if lra was successfully completed, false otherwise
      */
-    boolean isClosed();
+    boolean isComplete();
 
     /**
-     * @return  true if LRA was cancelled, false otherwise
+     * @return  true if lra was compensated, false otherwise
      */
-    boolean isCancelled();
+    boolean isCompensated();
 
     /**
-     * @return  true if recovery is in progress on the LRA, false otherwise
+     * @return  true if recovery is in progress on the lra, false otherwise
      */
     boolean isRecovering();
 
     /**
-     * @return  true if LRA is in active state right now, false otherwise
+     * @return  true if lra is in active state right now, false otherwise
      */
     boolean isActive();
 
     /**
-     * @return  true if LRA is top level (not nested), false otherwise
+     * @return  true if lra is top level (not nested), false otherwise
      */
     boolean isTopLevel();
 }
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/LraTckConfigBean.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/LraTckConfigBean.java
new file mode 100644
index 0000000..b0df98c
--- /dev/null
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/LraTckConfigBean.java
@@ -0,0 +1,103 @@
+/*
+ *******************************************************************************
+ * Copyright (c) 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+
+package org.eclipse.microprofile.lra.tck;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.lra.client.LRAClient;
+
+@ApplicationScoped
+public class LraTckConfigBean {
+
+    /**
+     * Definition of LRA default timeout which should be used
+     * by any method which needs to work with timeout
+     */
+    public static final Long LRA_TIMEOUT_MILLIS = 50000L;
+
+    /**
+     * <p>
+     * Timeout factor which adjusts waiting time and timeouts for the TCK suite.
+     * <p>
+     * The default value is set to <code>1.0</code> which means the defined timeout
+     * is multiplied by <code>1</code>.
+     * <p>
+     * If you wish the test waits longer then set the value bigger than <code>1.0</code>.
+     * If you wish the test waits shorter time than designed
+     * or the timeout is elapsed faster then set the value less than <code>1.0</code>
+     */
+    @Inject @ConfigProperty(name = "lra.tck.timeout.factor", defaultValue = "1.0")
+    private double timeoutFactor;
+
+    /**
+     * Host name where LRA recovery is expected to be launch and TCK suite tries to connect to it at.
+     * The port is specifed by {@link #recoveryPort}.
+     */
+    @Inject @ConfigProperty(name = LRAClient.LRA_RECOVERY_HOST_KEY, defaultValue = "localhost")
+    private String recoveryHostName;
+
+    /**
+     * Port where LRA recovery is expected to be launch and TCK suite tries to connect to it at.
+     * The hostname is specifed by {@link #recoveryHostName}.
+     */
+    @Inject @ConfigProperty(name = LRAClient.LRA_RECOVERY_PORT_KEY, defaultValue = "8080")
+    private int recoveryPort;
+
+    /**
+     * Path where recovery is available to accept requests.
+     * The hostname of LRA recovery is specifed by {@link #recoveryHostName},
+     * the port of LRA recovery is defined by {@link #recoveryPort}.
+     */
+    @Inject @ConfigProperty(name = LRAClient.LRA_RECOVERY_PATH_KEY, defaultValue = "lra-recovery-coordinator")
+    private String recoveryPath;
+
+    /**
+     * Base URL where the LRA suite is started at. It's URL where container exposes the test suite deployment.
+     * The test paths will be constructed based on this base URL.
+     * <p>
+     * The default base URL where TCK suite is expected to be started is <code>http://localhost:8180/</code>.
+     */
+    @Inject @ConfigProperty(name = "lra.tck.base.url", defaultValue = "http://localhost:8180/")
+    private String tckSuiteBaseUrl;
+
+
+    public double timeoutFactor() {
+        return timeoutFactor;
+    }
+
+    public String recoveryHostName() {
+        return recoveryHostName;
+    }
+
+    public int recoveryPort() {
+        return recoveryPort;
+    }
+
+    public String recoveryPath() {
+        return recoveryPath;
+    }
+
+    public String tckSuiteBaseUrl() {
+        return tckSuiteBaseUrl;
+    }
+}
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraCancelOnController.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraCancelOnController.java
new file mode 100644
index 0000000..d177117
--- /dev/null
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraCancelOnController.java
@@ -0,0 +1,200 @@
+/*
+ *******************************************************************************
+ * Copyright (c) 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package org.eclipse.microprofile.lra.tck.participant.api;
+
+import static org.eclipse.microprofile.lra.client.LRAClient.LRA_HTTP_HEADER;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.Response.Status.Family;
+
+import org.eclipse.microprofile.lra.annotation.Compensate;
+import org.eclipse.microprofile.lra.annotation.Complete;
+import org.eclipse.microprofile.lra.annotation.LRA;
+import org.eclipse.microprofile.lra.annotation.LRA.Type;
+import org.eclipse.microprofile.lra.tck.LraTckConfigBean;
+
+@ApplicationScoped
+@Path(LraCancelOnController.LRA_CANCEL_ON_CONTROLLER_PATH)
+public class LraCancelOnController {
+    private static final Logger LOGGER = Logger.getLogger(LraCancelOnController.class.getName());
+    public static final String LRA_CANCEL_ON_CONTROLLER_PATH = "lracontroller-cancelon";
+    public static final String COMPLETED_COUNT_PATH = "completed";
+    public static final String COMPENSATED_COUNT_PATH = "compensated";
+
+    private final AtomicInteger completedCount = new AtomicInteger(0);
+    private final AtomicInteger compensatedCount = new AtomicInteger(0);
+
+    @Inject
+    private LraTckConfigBean config;
+
+    public static final String CANCEL_ON_FAMILY_DEFAULT_4XX = "cancelOnFamilyDefault4xx";
+    /**
+     * Default return status for cancelling LRA is <code>4xx</code> and <code>5xx</code>
+     */
+    @GET
+    @Path(CANCEL_ON_FAMILY_DEFAULT_4XX)
+    @LRA(value = Type.REQUIRED)
+    public Response cancelOnFamilyDefault4xx() {
+        return Response.status(Status.BAD_REQUEST).build();
+    }
+
+    public static final String CANCEL_ON_FAMILY_DEFAULT_5XX = "cancelOnFamilyDefault5xx";
+    /**
+     * Default return status for cancelling LRA is <code>4xx</code> and <code>5xx</code>
+     */
+    @GET
+    @Path(CANCEL_ON_FAMILY_DEFAULT_5XX)
+    @LRA(value = Type.REQUIRED)
+    public Response cancelOnFamilyDefault5xx() {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+    public static final String CANCEL_ON_FAMILY_3XX = "cancelOnFamily3xx";
+    /**
+     * Cancel on family is set to <code>3xx</code>. The <code>3xx</code> return code
+     * has to cancel the LRA.
+     */
+    @GET
+    @Path(CANCEL_ON_FAMILY_3XX)
+    @LRA(value = Type.REQUIRES_NEW,
+            cancelOnFamily = Family.REDIRECTION)
+    public Response cancelOnFamily3xx() {
+        return Response.status(Status.SEE_OTHER).build();
+    }
+
+    public static final String CANCEL_ON_301 = "cancelOn301";
+    /**
+     * Cancel on is set to <code>301</code>. The <code>301</code> return code
+     * has to cancel the LRA.
+     */
+    @GET
+    @Path(CANCEL_ON_301)
+    @LRA(value = Type.REQUIRES_NEW,
+        cancelOn = {Status.MOVED_PERMANENTLY})
+    public Response cancelOn301() {
+        return Response.status(Status.MOVED_PERMANENTLY).build();
+    }
+
+    public static final String NOT_CANCEL_ON_FAMILY_5XX = "notCancelOnFamily5xx";
+    /**
+     * Cancel on family is set to <code>4xx</code>,
+     * the code from other families (e.g. for <code>5xx</code>
+     * should not cancel but should go with close the LRA.
+     */
+    @GET
+    @Path(NOT_CANCEL_ON_FAMILY_5XX)
+    @LRA(value = Type.REQUIRES_NEW,
+            cancelOnFamily = {Family.CLIENT_ERROR})
+    public Response notCancelOnFamily5xx() {
+        return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+    }
+
+    public static final String CANCEL_FROM_REMOTE_CALL = "cancelFromRemoteCall";
+    /**
+     * Returning <code>200</code> thus the LRA should be closed but
+     * it calls the remote method which ends with 5xx which is the
+     * default for the cancelling and so the whole LRA should be cancelled.
+     */
+    @GET
+    @Path(CANCEL_FROM_REMOTE_CALL)
+    @LRA(value = Type.REQUIRES_NEW)
+    public Response cancelFromRemoteCall() {
+        Client client = ClientBuilder.newClient();
+        try {
+            Response response = client
+                    .target(URI.create(new URL(config.tckSuiteBaseUrl()).toExternalForm()))
+                    .path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                    .path(LraCancelOnController.CANCEL_ON_FAMILY_DEFAULT_5XX)
+                    .request().get();
+            assert response.getStatus() == 500;
+        } catch (MalformedURLException murle) {
+            LOGGER.log(Level.SEVERE, "Cannot create url from string '"
+                    + config.tckSuiteBaseUrl() + "'", murle);
+            return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+        } finally {
+            client.close();
+        }
+        return Response.ok().build();
+    }
+
+
+    @PUT
+    @Path("/complete")
+    @Complete
+    public Response completeWork(@HeaderParam(LRA_HTTP_HEADER) String lraId)
+        throws NotFoundException {
+        if(lraId == null) {
+            throw new NullPointerException("lraId can't be null as it should be invoked with the context");
+        }
+
+        completedCount.incrementAndGet();
+
+        LOGGER.info(String.format("LRA id '%s' was completed", lraId));
+        return Response.ok().build();
+    }
+
+    @PUT
+    @Path("/compensate")
+    @Compensate
+    public Response compensateWork(@HeaderParam(LRA_HTTP_HEADER) String lraId, String userData)
+        throws NotFoundException {
+        if(lraId == null) {
+            throw new NullPointerException("lraId can't be null as it should be invoked with the context");
+        }
+
+        compensatedCount.incrementAndGet();
+
+        LOGGER.info(String.format("LRA id '%s' was compensated", lraId));
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path(COMPLETED_COUNT_PATH)
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response completed() {
+        return Response.ok(completedCount.toString()).build();
+    }
+
+    @GET
+    @Path(COMPENSATED_COUNT_PATH)
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response compensated() {
+        return Response.ok(compensatedCount.toString()).build();
+    }
+}
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java
index 3d14989..cf5eb93 100644
--- a/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/participant/api/LraController.java
@@ -432,30 +432,6 @@ public class LraController {
         return Response.ok(COMPENSATED_COUNT.get()).build();
     }
 
-    @GET
-    @Path("/cancelOn")
-    @Produces(MediaType.APPLICATION_JSON)
-    @LRA(value = LRA.Type.REQUIRED, cancelOn = {Response.Status.NOT_FOUND, Response.Status.BAD_REQUEST})
-    public Response cancelOn(@HeaderParam(LRA_HTTP_HEADER) String lraId) {
-        assertHeaderPresent(lraId);
-
-        activityStore.add(new Activity(lraId));
-
-        return Response.status(Response.Status.BAD_REQUEST).entity(Entity.text("Simulate buisiness logic failure")).build();
-    }
-
-    @GET
-    @Path("/cancelOnFamily")
-    @Produces(MediaType.APPLICATION_JSON)
-    @LRA(value = LRA.Type.REQUIRED, cancelOnFamily = {Response.Status.Family.CLIENT_ERROR})
-    public Response cancelOnFamily(@HeaderParam(LRA_HTTP_HEADER) String lraId) {
-        assertHeaderPresent(lraId);
-
-        activityStore.add(new Activity(lraId));
-
-        return Response.status(Response.Status.BAD_REQUEST).entity(Entity.text("Simulate buisiness logic failure")).build();
-    }
-
     @GET
     @Path("/timeLimit")
     @Produces(MediaType.APPLICATION_JSON)


Test patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckCancelOnTests.java b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckCancelOnTests.java
new file mode 100644
index 0000000..99c129b
--- /dev/null
+++ b/tck/src/main/java/org/eclipse/microprofile/lra/tck/TckCancelOnTests.java
@@ -0,0 +1,198 @@
+/*
+ *******************************************************************************
+ * Copyright (c) 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package org.eclipse.microprofile.lra.tck;
+
+import static org.eclipse.microprofile.lra.tck.participant.api.LraCancelOnController.LRA_CANCEL_ON_CONTROLLER_PATH;
+import static org.junit.Assert.assertEquals;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.logging.Logger;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.microprofile.lra.tck.participant.api.LraCancelOnController;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+@RunWith(Arquillian.class)
+@RunAsClient
+public class TckCancelOnTests {
+    private static final Logger LOGGER = Logger.getLogger(TckCancelOnTests.class.getName());
+
+
+    @Rule public TestName testName = new TestName();
+
+    private static final String TCK_SUITE_BASE_URL = System.getProperty("lra.tck.base.url", "http://localhost:8180");
+    private static Client tckSuiteClient;
+
+    private int beforeCompletedCount;
+    private int beforeCompensatedCount;
+
+    @Deployment(name = "tcktests-cancelon", managed = true, testable = true)
+    public static WebArchive deploy() {
+        String archiveName = TckCancelOnTests.class.getSimpleName().toLowerCase();
+        return ShrinkWrap
+            .create(WebArchive.class, archiveName + ".war")
+            .addPackages(true, "org.eclipse.microprofile.lra.tck")
+            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+    }
+
+    @BeforeClass
+    public static void beforeClass() {
+        tckSuiteClient = ClientBuilder.newClient();
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        if(tckSuiteClient != null) {
+            tckSuiteClient.close();
+        }
+    }
+
+    @Before
+    public void before() {
+        LOGGER.info("Running test: " + testName.getMethodName());
+        this.beforeCompletedCount = getCompletedCount();
+        this.beforeCompensatedCount = getCompensateCount();
+    }
+
+    private WebTarget getSuiteTarget() {
+        if(TCK_SUITE_BASE_URL == null) {
+            throw new NullPointerException("The test is not provided with the system property 'lra.tck.base.url'");
+        }
+        try {
+            return tckSuiteClient.target(URI.create(new URL(TCK_SUITE_BASE_URL).toExternalForm()));
+        } catch (MalformedURLException mfe) {
+            throw new IllegalStateException("Cannot create REST test target for the LRA TCK suite base url "
+                    + TCK_SUITE_BASE_URL, mfe);
+        }
+    }
+
+    /**
+     * See {@link LraCancelOnController#cancelOnFamilyDefault4xx()}
+     */
+    @Test
+    public void cancelOnFamilyDefault4xx() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.CANCEL_ON_FAMILY_DEFAULT_4XX).request().get();
+        assertEquals("The 400 status response is expected", Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+        assertEquals("After 400 compensate should be invoked", beforeCompensatedCount + 1, getCompensateCount());
+        assertEquals("After 400 complete can't be invoked", beforeCompletedCount, getCompletedCount());
+    }
+
+    /**
+     * See {@link LraCancelOnController#cancelOnFamilyDefault5xx()}
+     */
+    @Test
+    public void cancelOnFamilyDefault5xx() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.CANCEL_ON_FAMILY_DEFAULT_5XX).request().get();
+        assertEquals("The 500 status response is expected", Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
+        assertEquals("After 500 compensate should be invoked", beforeCompensatedCount + 1, getCompensateCount());
+        assertEquals("After 500 complete can't be invoked", beforeCompletedCount, getCompletedCount());
+    }
+
+    /**
+     * See {@link LraCancelOnController#cancelOnFamily3xx()}
+     */
+    @Test
+    public void cancelOnFamily3xx() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.CANCEL_ON_FAMILY_3XX).request().get();
+        assertEquals("The 303 status response is expected", Status.SEE_OTHER.getStatusCode(), response.getStatus());
+        assertEquals("After status code 303 is received, compensate should be invoked as set by attribute cancelOnFamily",
+                beforeCompensatedCount + 1, getCompensateCount());
+        assertEquals("After status code 303 is received, complete can't be invoked as not defined in annotation @LRA",
+                beforeCompletedCount, getCompletedCount());
+    }
+
+    /**
+     * See {@link LraCancelOnController#cancelOn301()}
+     */
+    @Test
+    public void cancelOn301() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.CANCEL_ON_301).request().get();
+        assertEquals("The 301 status response is expected", Status.MOVED_PERMANENTLY.getStatusCode(), response.getStatus());
+        assertEquals("After status code 301 is received, compensate should be invoked as set by attribute cancelOn",
+                beforeCompensatedCount + 1, getCompensateCount());
+        assertEquals("After status code 301 is received, complete can't be invoked as not defined in annotation @LRA",
+                beforeCompletedCount, getCompletedCount());
+    }
+
+    /**
+     * See {@link LraCancelOnController#notCancelOnFamily5xx()}
+     */
+    @Test
+    public void notCancelOnFamily5xx() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.NOT_CANCEL_ON_FAMILY_5XX).request().get();
+        assertEquals("The 500 status response is expected", Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
+        assertEquals("After status code 500 is received, compensate can't be invoked as default behaviour was changed",
+                beforeCompensatedCount, getCompensateCount());
+        assertEquals("After status code 500 is received, complete has to be called as default behaviour was changed",
+                beforeCompletedCount + 1, getCompletedCount());
+    }
+
+    /**
+     * See {@link LraCancelOnController#cancelFromRemoteCall()}
+     */
+    @Test
+    public void cancelFromRemoteCall() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.CANCEL_FROM_REMOTE_CALL).request().get();
+        assertEquals("The 200 status response is expected", Status.OK.getStatusCode(), response.getStatus());
+        assertEquals("Status was 200 but compensate should be called twice as LRA should be cancelled for remotely called participant as well",
+                beforeCompensatedCount + 2, getCompensateCount());
+        assertEquals("Even the 200 status was received the remotly called participant should cause the LRA being cancelled",
+                beforeCompletedCount, getCompletedCount());
+    }
+
+
+
+    private int getCompletedCount() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.COMPLETED_COUNT_PATH).request().get();
+        return response.readEntity(Integer.class);
+    }
+
+    private int getCompensateCount() {
+        Response response = getSuiteTarget().path(LRA_CANCEL_ON_CONTROLLER_PATH)
+                .path(LraCancelOnController.COMPENSATED_COUNT_PATH).request().get();
+        return Integer.valueOf(response.readEntity(String.class));
+    }
+}
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 54eeccc..c434bc9 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
@@ -24,7 +24,6 @@ import static org.eclipse.microprofile.lra.tck.participant.api.LraController.LRA
 import static org.eclipse.microprofile.lra.tck.participant.api.LraController.TRANSACTIONAL_WORK_PATH;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -41,7 +40,6 @@ import java.util.logging.Logger;
 import java.util.stream.IntStream;
 
 import javax.inject.Inject;
-import javax.ws.rs.NotFoundException;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
@@ -49,7 +47,6 @@ import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
-import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipse.microprofile.lra.annotation.LRAStatus;
 import org.eclipse.microprofile.lra.client.LRAClient;
 import org.eclipse.microprofile.lra.tck.participant.api.LraController;
@@ -73,55 +70,13 @@ import org.junit.runner.RunWith;
 @RunWith(Arquillian.class)
 public class TckTests {
     private static final Logger LOGGER = Logger.getLogger(TckTests.class.getName());
-    private final Long LRA_TIMEOUT_MILLIS = 50000L;
 
-    /**
-     * <p>
-     * Timeout factor which adjusts waiting time and timeouts for the TCK suite.
-     * <p>
-     * The default value is set to <code>1.0</code> which means the defined timeout
-     * is multiplied by <code>1</code>.
-     * <p>
-     * If you wish the test waits longer then set the value bigger than <code>1.0</code>.
-     * If you wish the test waits shorter time than designed
-     * or the timeout is elapsed faster then set the value less than <code>1.0</code> 
-     */
-    @Inject @ConfigProperty(name = "lra.tck.timeout.factor", defaultValue = "1.0")
-    private double timeoutFactor;
-    
-    /**
-     * Host name where LRA recovery is expected to be launch and TCK suite tries to connect to it at.
-     * The port is specifed by {@link #recoveryPort}.
-     */
-    @Inject @ConfigProperty(name = LRAClient.LRA_RECOVERY_HOST_KEY, defaultValue = "localhost")
-    private String recoveryHostName;
-    
-    /**
-     * Port where LRA recovery is expected to be launch and TCK suite tries to connect to it at.
-     * The hostname is specifed by {@link #recoveryHostName}.
-     */
-    @Inject @ConfigProperty(name = LRAClient.LRA_RECOVERY_PORT_KEY, defaultValue = "8080")
-    private int recoveryPort;
-    
-    /**
-     * Path where recovery is available to accept requests.
-     * The hostname of LRA recovery is specifed by {@link #recoveryHostName},
-     * the port of LRA recovery is defined by {@link #recoveryPort}.
-     */
-    @Inject @ConfigProperty(name = LRAClient.LRA_RECOVERY_PATH_KEY, defaultValue = "lra-recovery-coordinator")
-    private String recoveryPath;
-
-    /**
-     * Base URL of LRA suite is started at. It's URL where container exposes the test suite deployment.
-     * The test paths will be constructed based on this base URL.
-     * <p>
-     * The default base URL where TCK suite is expected to be started is <code>http://localhost:8180/</code>.
-     */
-    @Inject @ConfigProperty(name = "lra.tck.base.url", defaultValue = "http://localhost:8180/")
-    private String tckSuiteBaseUrl;
 
     @Rule public TestName testName = new TestName();
 
+    @Inject
+    private LraTckConfigBean config;
+
     @Inject
     private LRAClient lraClient;
 
@@ -166,9 +121,9 @@ public class TckTests {
         setUpTestCase();
 
         try {
-            tckSuiteTarget = tckSuiteClient.target(URI.create(new URL(tckSuiteBaseUrl).toExternalForm()));
+            tckSuiteTarget = tckSuiteClient.target(URI.create(new URL(config.tckSuiteBaseUrl()).toExternalForm()));
         } catch (MalformedURLException mfe) {
-            throw new IllegalStateException("Cannot create URL for the LRA TCK suite base url " + tckSuiteBaseUrl, mfe);
+            throw new IllegalStateException("Cannot create URL for the LRA TCK suite base url " + config.tckSuiteBaseUrl(), mfe);
         }
         recoveryTarget = recoveryCoordinatorClient.target(URI.create(recoveryCoordinatorBaseUrl.toExternalForm()));
     }
@@ -205,7 +160,8 @@ public class TckTests {
 
         try {
             // TODO: what to do with this? recovery tests are valid?
-            recoveryCoordinatorBaseUrl = new URL(String.format("http://%s:%d/%s", recoveryHostName, recoveryPort, recoveryPath));
+            recoveryCoordinatorBaseUrl = new URL(String.format("http://%s:%d/%s",
+                    config.recoveryHostName(), config.recoveryPort(), config.recoveryPath()));
 
             tckSuiteClient = ClientBuilder.newClient();
             recoveryCoordinatorClient = ClientBuilder.newClient();
@@ -561,16 +517,6 @@ public class TckTests {
         lraClient.closeLRA(new URL(lraHeader.toString()));
     }
 
-    @Test
-    public void cancelOn() {
-        cancelCheck("cancelOn");
-    }
-
-    @Test
-    public void cancelOnFamily() {
-        cancelCheck("cancelOnFamily");
-    }
-
     @Test
     public void timeLimit() {
         int beforeCompletedCount = getCompletedCount();
@@ -909,39 +855,6 @@ public class TckTests {
         }
     }
 
-    private void cancelCheck(String path) {
-        int beforeCompletedCount = getCompletedCount();
-        int beforeCompensatedCount = getCompensatedCount();
-
-        URL lra = lraClient.startLRA(null, "SpecTest#" + path, lraTimeout(), ChronoUnit.MILLIS);
-
-        WebTarget resourcePath = tckSuiteTarget.path(LRA_CONTROLLER_PATH).path(path);
-
-        Response response = resourcePath
-                .request()
-                .header(LRAClient.LRA_HTTP_HEADER, lra)
-                .get();
-
-        checkStatusReadAndClose(Response.Status.BAD_REQUEST, response, resourcePath);
-
-        // check that participant was invoked
-        int completedCount = getCompletedCount();
-        int compensatedCount = getCompensatedCount();
-
-        // check that complete was not called and that compensate was
-        assertEquals("complete was called instead of compensate (called to " + resourcePath.getUri() + ")",
-                beforeCompletedCount, completedCount);
-        assertEquals("compensate should have been called (called to " + resourcePath.getUri() + ")",
-                beforeCompensatedCount + 1, compensatedCount);
-
-        try {
-            assertNotEquals("LRA '" + lra + "' should have been cancelled (called to " + resourcePath.getUri() + ")",
-                    LRAStatus.Active, lraClient.getStatus(lra));
-        } catch (NotFoundException ignore) {
-            // means the LRA has gone
-        }
-    }
-
     private boolean containsLraId(List<LRAInfo> lras, URL lraIdURL) {
         String lraId = lraIdURL.toExternalForm();
         return containsLraId(lras, lraId);
@@ -963,6 +876,6 @@ public class TckTests {
      * which can be defined by user.
      */
     private long lraTimeout() {
-        return Util.adjust(LRA_TIMEOUT_MILLIS, timeoutFactor);
+        return Util.adjust(LraTckConfigBean.LRA_TIMEOUT_MILLIS, config.timeoutFactor());
     }
 }