You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2016/09/26 21:58:50 UTC

[5/6] activemq-artemis git commit: ARTEMIS-737 Improving Tests by checking thread leaks and Waiting condition, also adding docs

ARTEMIS-737 Improving Tests by checking thread leaks and Waiting condition, also adding docs


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/03b3b9fa
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/03b3b9fa
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/03b3b9fa

Branch: refs/heads/master
Commit: 03b3b9fa80028dcb736c33f6f8e41f22584aa3b9
Parents: 32b7c03
Author: Clebert Suconic <cl...@apache.org>
Authored: Mon Sep 26 15:33:39 2016 -0400
Committer: Clebert Suconic <cl...@apache.org>
Committed: Mon Sep 26 17:58:05 2016 -0400

----------------------------------------------------------------------
 .../artemis/junit/ActiveMQConsumerResource.java |   2 +-
 .../artemis/junit/ThreadLeakCheckRule.java      | 223 +++++++++++++++++++
 .../org/apache/activemq/artemis/junit/Wait.java |  55 +++++
 .../junit/ActiveMQConsumerResourceTest.java     |  10 +-
 .../ActiveMQDynamicProducerResourceTest.java    |   8 +-
 ...ucerResourceWithoutAddressExceptionTest.java |   2 +-
 ...namicProducerResourceWithoutAddressTest.java |   8 +-
 .../junit/ActiveMQProducerResourceTest.java     |   2 +-
 ...ActiveMQResourceCustomConfigurationTest.java |   5 +-
 ...edActiveMQResourceFileConfigurationTest.java |   6 +-
 .../junit/EmbeddedActiveMQResourceTest.java     |  11 +-
 ...MSResourceMultipleFileConfigurationTest.java |   5 +-
 .../junit/EmbeddedJMSResourceQueueTest.java     |  11 +-
 ...dJMSResourceSingleFileConfigurationTest.java |   5 +-
 .../junit/EmbeddedJMSResourceTopicTest.java     |  11 +-
 .../MultipleEmbeddedActiveMQResourcesTest.java  |   6 +-
 .../junit/MultipleEmbeddedJMSResourcesTest.java |   6 +-
 docs/user-manual/en/SUMMARY.md                  |   1 +
 docs/user-manual/en/unit-testing.md             |  77 +++++++
 19 files changed, 437 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java b/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java
index d48ef1d..200ce92 100644
--- a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java
+++ b/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java
@@ -31,7 +31,7 @@ import org.apache.activemq.artemis.api.core.client.ServerLocator;
  * <pre><code>
  * public class SimpleTest {
  *    {@code @Rule}
- *     public ActiveMQConsumerResource producer = new ActiveMQProducerResource( "vm://0", "test.queue" );
+ *     public ActiveMQConsumerResource client = new ActiveMQProducerResource( "vm://0", "test.queue" );
  *
  *    {@code @Test}
  *     public void testSomething() throws Exception {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ThreadLeakCheckRule.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ThreadLeakCheckRule.java b/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ThreadLeakCheckRule.java
new file mode 100644
index 0000000..43da4f5
--- /dev/null
+++ b/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ThreadLeakCheckRule.java
@@ -0,0 +1,223 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.artemis.junit;
+
+import java.lang.ref.WeakReference;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
+import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnector;
+import org.jboss.logging.Logger;
+import org.junit.Assert;
+import org.junit.rules.ExternalResource;
+
+/**
+ * Messaging tests are usually Thread intensive and a thread leak or a server leakage may affect future tests.
+ * This Rule will prevent Threads leaking from one test into another by checking left over threads.
+ * This will also clear Client Thread Pools from ActiveMQClient.
+ */
+public class ThreadLeakCheckRule extends ExternalResource {
+   private static Logger log = Logger.getLogger(ThreadLeakCheckRule.class);
+
+   private static Set<String> knownThreads = new HashSet<>();
+
+   boolean enabled = true;
+
+   private Map<Thread, StackTraceElement[]> previousThreads;
+
+   public void disable() {
+      enabled = false;
+   }
+
+   /**
+    * Override to set up your specific external resource.
+    *
+    * @throws if setup fails (which will disable {@code after}
+    */
+   @Override
+   protected void before() throws Throwable {
+      // do nothing
+
+      previousThreads = Thread.getAllStackTraces();
+
+   }
+
+   /**
+    * Override to tear down your specific external resource.
+    */
+   @Override
+   protected void after() {
+      ActiveMQClient.clearThreadPools();
+      InVMConnector.resetThreadPool();
+
+      try {
+         if (enabled) {
+            boolean failed = true;
+
+            boolean failedOnce = false;
+
+            long timeout = System.currentTimeMillis() + 60000;
+            while (failed && timeout > System.currentTimeMillis()) {
+               failed = checkThread();
+
+               if (failed) {
+                  failedOnce = true;
+                  forceGC();
+                  try {
+                     Thread.sleep(500);
+                  }
+                  catch (Throwable e) {
+                  }
+               }
+            }
+
+            if (failed) {
+               Assert.fail("Thread leaked");
+            }
+            else if (failedOnce) {
+               System.out.println("******************** Threads cleared after retries ********************");
+               System.out.println();
+            }
+
+         }
+         else {
+            enabled = true;
+         }
+      }
+      finally {
+         // clearing just to help GC
+         previousThreads = null;
+      }
+
+   }
+
+   private static int failedGCCalls = 0;
+
+   public static void forceGC() {
+
+      if (failedGCCalls >= 10) {
+         log.info("ignoring forceGC call since it seems System.gc is not working anyways");
+         return;
+      }
+      log.info("#test forceGC");
+      CountDownLatch finalized = new CountDownLatch(1);
+      WeakReference<DumbReference> dumbReference = new WeakReference<>(new DumbReference(finalized));
+
+      long timeout = System.currentTimeMillis() + 1000;
+
+      // A loop that will wait GC, using the minimal time as possible
+      while (!(dumbReference.get() == null && finalized.getCount() == 0) && System.currentTimeMillis() < timeout) {
+         System.gc();
+         System.runFinalization();
+         try {
+            finalized.await(100, TimeUnit.MILLISECONDS);
+         }
+         catch (InterruptedException e) {
+         }
+      }
+
+      if (dumbReference.get() != null) {
+         failedGCCalls++;
+         log.info("It seems that GC is disabled at your VM");
+      }
+      else {
+         // a success would reset the count
+         failedGCCalls = 0;
+      }
+      log.info("#test forceGC Done ");
+   }
+   public static void removeKownThread(String name) {
+      knownThreads.remove(name);
+   }
+
+   public static void addKownThread(String name) {
+      knownThreads.add(name);
+   }
+
+   private boolean checkThread() {
+      boolean failedThread = false;
+
+      Map<Thread, StackTraceElement[]> postThreads = Thread.getAllStackTraces();
+
+      if (postThreads != null && previousThreads != null && postThreads.size() > previousThreads.size()) {
+
+
+         for (Thread aliveThread : postThreads.keySet()) {
+            if (aliveThread.isAlive() && !isExpectedThread(aliveThread) && !previousThreads.containsKey(aliveThread)) {
+               if (!failedThread) {
+                  System.out.println("*********************************************************************************");
+                  System.out.println("LEAKING THREADS");
+               }
+               failedThread = true;
+               System.out.println("=============================================================================");
+               System.out.println("Thread " + aliveThread + " is still alive with the following stackTrace:");
+               StackTraceElement[] elements = postThreads.get(aliveThread);
+               for (StackTraceElement el : elements) {
+                  System.out.println(el);
+               }
+            }
+
+         }
+         if (failedThread) {
+            System.out.println("*********************************************************************************");
+         }
+      }
+
+
+      return failedThread;
+   }
+
+
+   /**
+    * if it's an expected thread... we will just move along ignoring it
+    *
+    * @param thread
+    * @return
+    */
+   private boolean isExpectedThread(Thread thread) {
+
+      for (String known: knownThreads) {
+         if (thread.getName().contains(known)) {
+            return true;
+         }
+      }
+
+      return false;
+   }
+
+
+   protected static class DumbReference {
+
+      private CountDownLatch finalized;
+
+      public DumbReference(CountDownLatch finalized) {
+         this.finalized = finalized;
+      }
+
+      @Override
+      public void finalize() throws Throwable {
+         finalized.countDown();
+         super.finalize();
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/Wait.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/Wait.java b/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/Wait.java
new file mode 100644
index 0000000..fe8fba0
--- /dev/null
+++ b/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/Wait.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.artemis.junit;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Utility adapted from: org.apache.activemq.util.Wait
+ */
+public class Wait {
+
+   public static final long MAX_WAIT_MILLIS = 30 * 1000;
+   public static final int SLEEP_MILLIS = 1000;
+
+   public interface Condition {
+
+      boolean isSatisfied() throws Exception;
+   }
+
+   public static boolean waitFor(Condition condition) throws Exception {
+      return waitFor(condition, MAX_WAIT_MILLIS);
+   }
+
+   public static boolean waitFor(final Condition condition, final long duration) throws Exception {
+      return waitFor(condition, duration, SLEEP_MILLIS);
+   }
+
+   public static boolean waitFor(final Condition condition,
+                                 final long duration,
+                                 final long sleepMillis) throws Exception {
+
+      final long expiry = System.currentTimeMillis() + duration;
+      boolean conditionSatisified = condition.isSatisfied();
+      while (!conditionSatisified && System.currentTimeMillis() < expiry) {
+         TimeUnit.MILLISECONDS.sleep(sleepMillis);
+         conditionSatisified = condition.isSatisfied();
+      }
+      return conditionSatisified;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
index b8a637a..08a2d80 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
@@ -50,14 +50,22 @@ public class ActiveMQConsumerResourceTest {
 
    ActiveMQConsumerResource consumer = new ActiveMQConsumerResource(server.getVmURL(), TEST_QUEUE);
 
+
    @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(consumer);
+   public RuleChain ruleChain = RuleChain.outerRule(new ThreadLeakCheckRule()).outerRule(server).around(consumer);
+
 
    ClientMessage sent = null;
 
    @After
    public void tearDown() throws Exception {
       assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS), sent);
+      Wait.waitFor(new Wait.Condition() {
+         @Override
+         public boolean isSatisfied() throws Exception {
+            return server.getMessageCount("TEST_QUEUE") == 1;
+         }
+      }, 5000, 100);
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_QUEUE), 1, server.getMessageCount(TEST_QUEUE));
 
       ClientMessage received = consumer.receiveMessage();

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
index 7d09848..da3990c 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
@@ -51,7 +51,7 @@ public class ActiveMQDynamicProducerResourceTest {
    ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL(), TEST_QUEUE_ONE);
 
    @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   public RuleChain ruleChain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server).around(producer);
 
    ClientMessage sentOne = null;
    ClientMessage sentTwo = null;
@@ -60,6 +60,12 @@ public class ActiveMQDynamicProducerResourceTest {
    public void tearDown() throws Exception {
       assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE), sentOne);
       assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO), sentTwo);
+      Wait.waitFor(new Wait.Condition() {
+         @Override
+         public boolean isSatisfied() throws Exception {
+            return server.getMessageCount(TEST_QUEUE_ONE) == 1 && server.getMessageCount(TEST_QUEUE_TWO) == 1;
+         }
+      }, 5000, 100);
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_QUEUE_ONE), 1, server.getMessageCount(TEST_QUEUE_ONE));
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_QUEUE_TWO), 1, server.getMessageCount(TEST_QUEUE_TWO));
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
index 5367009..7f6cbb4 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
@@ -43,7 +43,7 @@ public class ActiveMQDynamicProducerResourceWithoutAddressExceptionTest {
    ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL());
 
    @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   public RuleChain ruleChain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server).around(producer);
 
    ClientMessage sentOne = null;
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
index 6e61a3a..e57e175 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
@@ -52,7 +52,7 @@ public class ActiveMQDynamicProducerResourceWithoutAddressTest {
    ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL());
 
    @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   public RuleChain ruleChain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server).around(producer);
 
    ClientMessage sentOne = null;
    ClientMessage sentTwo = null;
@@ -68,6 +68,12 @@ public class ActiveMQDynamicProducerResourceWithoutAddressTest {
    public void tearDown() throws Exception {
       assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE), sentOne);
       assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO), sentTwo);
+      Wait.waitFor(new Wait.Condition() {
+         @Override
+         public boolean isSatisfied() throws Exception {
+            return server.getMessageCount(TEST_QUEUE_ONE) == 1 && server.getMessageCount(TEST_QUEUE_TWO) == 1;
+         }
+      }, 5000, 100);
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_QUEUE_ONE), 1, server.getMessageCount(TEST_QUEUE_ONE));
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_QUEUE_TWO), 1, server.getMessageCount(TEST_QUEUE_TWO));
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
index b0fd086..df9977d 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
@@ -50,7 +50,7 @@ public class ActiveMQProducerResourceTest {
    ActiveMQProducerResource producer = new ActiveMQProducerResource(server.getVmURL(), TEST_ADDRESS);
 
    @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   public RuleChain ruleChain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server).around(producer);
 
    ClientMessage sent = null;
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
index 13a6f52..fae54cc 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
@@ -24,6 +24,7 @@ import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
 import org.apache.activemq.artemis.core.server.Queue;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -37,8 +38,10 @@ public class EmbeddedActiveMQResourceCustomConfigurationTest {
    CoreQueueConfiguration queueConfiguration = new CoreQueueConfiguration().setAddress(TEST_ADDRESS).setName(TEST_QUEUE);
    Configuration customConfiguration = new ConfigurationImpl().setPersistenceEnabled(false).setSecurityEnabled(true).addQueueConfiguration(queueConfiguration);
 
+   private EmbeddedActiveMQResource server = new EmbeddedActiveMQResource(customConfiguration);
+
    @Rule
-   public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource(customConfiguration);
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server);
 
    @Test
    public void testCustomConfiguration() throws Exception {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
index 80ed251..ef10173 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
@@ -21,6 +21,7 @@ import java.util.List;
 import org.apache.activemq.artemis.core.server.Queue;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -31,8 +32,11 @@ public class EmbeddedActiveMQResourceFileConfigurationTest {
    static final String TEST_QUEUE = "test.queue";
    static final String TEST_ADDRESS = "test.address";
 
+   private EmbeddedActiveMQResource server = new EmbeddedActiveMQResource("embedded-artemis-server.xml");
+
    @Rule
-   public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource("embedded-artemis-server.xml");
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server);
+
 
    @Test
    public void testConfiguredQueue() throws Exception {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
index 876695d..36f8ad9 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
@@ -25,6 +25,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -46,9 +47,11 @@ public class EmbeddedActiveMQResourceTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   @Rule
    public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
 
+   @Rule
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server);
+
    ClientMessage sent = null;
 
    @Before
@@ -59,6 +62,12 @@ public class EmbeddedActiveMQResourceTest {
    @After
    public void tearDown() throws Exception {
       assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS), sent);
+      Wait.waitFor(new Wait.Condition() {
+         @Override
+         public boolean isSatisfied() throws Exception {
+            return server.getMessageCount(TEST_QUEUE) == 1;
+         }
+      }, 5000, 100);
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_QUEUE), 1, server.getMessageCount(TEST_QUEUE));
 
       ClientMessage received = server.receiveMessage(TEST_QUEUE);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java
index aa96ab7..ceb06e8 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java
@@ -29,6 +29,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -42,9 +43,11 @@ public class EmbeddedJMSResourceMultipleFileConfigurationTest {
    static final String ASSERT_PUSHED_FORMAT = "Message should have been pushed a message to %s";
    static final String ASSERT_COUNT_FORMAT = "Unexpected message count in destination %s";
 
-   @Rule
    public EmbeddedJMSResource jmsServer = new EmbeddedJMSResource("embedded-artemis-minimal-server.xml", "embedded-artemis-jms-only.xml");
 
+   @Rule
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(jmsServer);
+
    ConnectionFactory connectionFactory;
    Connection connection;
    Session session;

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java
index 19b04aa..bb2bf6b 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -48,14 +49,22 @@ public class EmbeddedJMSResourceQueueTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   @Rule
    public EmbeddedJMSResource jmsServer = new EmbeddedJMSResource();
 
+   @Rule
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(jmsServer);
+
    Message pushed = null;
 
    @After
    public void tearDown() throws Exception {
       assertNotNull(String.format(ASSERT_PUSHED_FORMAT, TEST_DESTINATION_NAME), pushed);
+      Wait.waitFor(new Wait.Condition() {
+         @Override
+         public boolean isSatisfied() throws Exception {
+            return jmsServer.getMessageCount(TEST_DESTINATION_NAME) == 1;
+         }
+      }, 5000, 100);
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_DESTINATION_NAME), 1, jmsServer.getMessageCount(TEST_DESTINATION_NAME));
    }
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java
index cdcbcaa..5ca3560 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java
@@ -29,6 +29,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -42,9 +43,11 @@ public class EmbeddedJMSResourceSingleFileConfigurationTest {
    static final String ASSERT_PUSHED_FORMAT = "Message should have been pushed a message to %s";
    static final String ASSERT_COUNT_FORMAT = "Unexpected message count in destination %s";
 
-   @Rule
    public EmbeddedJMSResource jmsServer = new EmbeddedJMSResource("embedded-artemis-jms-server.xml");
 
+   @Rule
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(jmsServer);
+
    ConnectionFactory connectionFactory;
    Connection connection;
    Session session;

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java
index d4dd738..0bccba1 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java
@@ -31,6 +31,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -55,9 +56,11 @@ public class EmbeddedJMSResourceTopicTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   @Rule
    public EmbeddedJMSResource jmsServer = new EmbeddedJMSResource();
 
+   @Rule
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(jmsServer);
+
    Message pushed = null;
 
    ConnectionFactory connectionFactory;
@@ -77,6 +80,12 @@ public class EmbeddedJMSResourceTopicTest {
    @After
    public void tearDown() throws Exception {
       assertNotNull(String.format(ASSERT_PUSHED_FORMAT, TEST_DESTINATION_NAME), pushed);
+      Wait.waitFor(new Wait.Condition() {
+         @Override
+         public boolean isSatisfied() throws Exception {
+            return jmsServer.getMessageCount(TEST_DESTINATION_NAME) == 1;
+         }
+      }, 5000, 100);
       assertEquals(String.format(ASSERT_COUNT_FORMAT, TEST_DESTINATION_NAME), 1, jmsServer.getMessageCount(TEST_DESTINATION_NAME));
 
       consumer.close();

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
index 97f1f5b..2fa1057 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
@@ -21,6 +21,7 @@ import org.apache.activemq.artemis.api.core.client.ClientMessage;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertNotNull;
 
@@ -37,12 +38,13 @@ public class MultipleEmbeddedActiveMQResourcesTest {
    static final String ASSERT_RECEIVED_FORMAT = "Message should have been received from %s";
    static final String ASSERT_COUNT_FORMAT = "Unexpected message count in queue %s";
 
-   @Rule
    public EmbeddedActiveMQResource serverOne = new EmbeddedActiveMQResource(0);
 
-   @Rule
    public EmbeddedActiveMQResource serverTwo = new EmbeddedActiveMQResource(1);
 
+   @Rule
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(serverOne).around(serverTwo);
+
    @Before
    public void setUp() throws Exception {
       serverOne.createQueue(TEST_ADDRESS_ONE, TEST_QUEUE_ONE);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java
----------------------------------------------------------------------
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java
index 1a5381c..e2b8416 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java
+++ b/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java
@@ -20,6 +20,7 @@ import javax.jms.Message;
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -33,12 +34,13 @@ public class MultipleEmbeddedJMSResourcesTest {
    static final String ASSERT_PUSHED_FORMAT = "Message should have been pushed a message to %s";
    static final String ASSERT_COUNT_FORMAT = "Unexpected message count in destination %s";
 
-   @Rule
    public EmbeddedJMSResource jmsServerOne = new EmbeddedJMSResource(0);
 
-   @Rule
    public EmbeddedJMSResource jmsServerTwo = new EmbeddedJMSResource(1);
 
+   @Rule
+   public RuleChain rulechain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(jmsServerOne).around(jmsServerTwo);
+
    @Test
    public void testMultipleServers() throws Exception {
       Message pushedOne = jmsServerOne.pushMessage(TEST_QUEUE_ONE, TEST_BODY);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/docs/user-manual/en/SUMMARY.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/SUMMARY.md b/docs/user-manual/en/SUMMARY.md
index 57d83ab..166fee1 100644
--- a/docs/user-manual/en/SUMMARY.md
+++ b/docs/user-manual/en/SUMMARY.md
@@ -56,6 +56,7 @@
 * [Protocols and Interoperability](protocols-interoperability.md)
 * [Tools](tools.md)
 * [Maven Plugin](maven-plugin.md)
+* [Unit Testing](unit-testing.md)
 * [Troubleshooting and Performance Tuning](perf-tuning.md)
 * [Configuration Reference](configuration-index.md)
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/03b3b9fa/docs/user-manual/en/unit-testing.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/unit-testing.md b/docs/user-manual/en/unit-testing.md
new file mode 100644
index 0000000..7beb311
--- /dev/null
+++ b/docs/user-manual/en/unit-testing.md
@@ -0,0 +1,77 @@
+# Unit Testing
+
+The package ```artemis-junit``` provides tools to facilitate how to run Artemis resources inside Junit Tests.
+
+These are provided as junit rules and can make it easier to embed Messaging functionality on your tests.
+
+
+## Example
+
+
+### Import this on your pom.xml
+
+```xml
+<dependency>
+  <groupId>org.apache.activemq</groupId>
+  <artifactId>artemis-junit</artifactId>
+  <!-- replace this for the version you are using -->
+  <version>1.5.0</version>
+  <scope>test</scope>
+</dependency>
+```
+
+
+### Declare a rule on your JUnit Test
+
+
+```java
+import org.apache.activemq.artemis.junit.EmbeddedJMSResource;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class MyTest {
+
+   @Rule
+   public EmbeddedJMSResource resource = new EmbeddedJMSResource();
+
+   @Test
+   public void myTest() {
+
+   }
+}
+```
+
+This will start a server that will be available for your test:
+
+```
+ain] 17:00:16,644 INFO  [org.apache.activemq.artemis.core.server] AMQ221000: live Message Broker is starting with configuration Broker Configuration (clustered=false,journalDirectory=data/journal,bindingsDirectory=data/bindings,largeMessagesDirectory=data/largemessages,pagingDirectory=data/paging)
+[main] 17:00:16,666 INFO  [org.apache.activemq.artemis.core.server] AMQ221045: libaio is not available, switching the configuration into NIO
+[main] 17:00:16,688 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-server]. Adding protocol support for: CORE
+[main] 17:00:16,801 INFO  [org.apache.activemq.artemis.core.server] AMQ221007: Server is now live
+[main] 17:00:16,801 INFO  [org.apache.activemq.artemis.core.server] AMQ221001: Apache ActiveMQ Artemis Message Broker version 1.5.0-SNAPSHOT [embedded-jms-server, nodeID=39e78380-842c-11e6-9e43-f45c8992f3c7] 
+[main] 17:00:16,891 INFO  [org.apache.activemq.artemis.core.server] AMQ221002: Apache ActiveMQ Artemis Message Broker version 1.5.0-SNAPSHOT [39e78380-842c-11e6-9e43-f45c8992f3c7] stopped, uptime 0.272 seconds
+
+```
+
+
+### Ordering rules
+
+This is actually a Junit feature, but this could be helpful on pre-determining the order on which rules are executed. 
+
+```java
+   ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL());
+
+   @Rule
+   public RuleChain ruleChain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server).around(producer);
+
+```
+
+### Available Rules
+
+Name | Description
+:--- | :---
+EmbeddedActiveMQResource | It will run a Server, without the JMS manager	
+EmbeddedJMSResource | It will run a Server, including the JMS Manager
+ActiveMQConsumerResource | It will automate the creation of a consumer		
+ActiveMQProducerResource | It will automate the creation of a producer
+ThreadLeakCheckRule | It will check that all threads have been finished after the test is finished