You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by st...@apache.org on 2017/01/20 07:03:44 UTC

[01/13] incubator-rocketmq git commit: [ROCKETMQ-37] Polish log output information in MQClientManager, closes apache/incubator-rocketmq#33, closes apache/incubator-rocketmq#26

Repository: incubator-rocketmq
Updated Branches:
  refs/heads/ROCKETMQ-57 0de84e20f -> 63de56c7b


[ROCKETMQ-37] Polish log output information in MQClientManager, closes apache/incubator-rocketmq#33, closes apache/incubator-rocketmq#26


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/69361f60
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/69361f60
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/69361f60

Branch: refs/heads/ROCKETMQ-57
Commit: 69361f60b70436996e3479e2ed4473f4f1ca2af1
Parents: 4291348
Author: a2888409 <12...@qq.com>
Authored: Fri Jan 20 10:55:48 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Fri Jan 20 10:55:48 2017 +0800

----------------------------------------------------------------------
 .../rocketmq/broker/subscription/SubscriptionGroupManager.java    | 2 +-
 .../java/org/apache/rocketmq/client/impl/MQClientManager.java     | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/69361f60/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
index 92dc5e7..bdf2a01 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
@@ -184,7 +184,7 @@ public class SubscriptionGroupManager extends ConfigManager {
             this.dataVersion.nextVersion();
             this.persist();
         } else {
-            log.warn("delete subscription group failed, subscription group: {} not exist", old);
+            log.warn("delete subscription group failed, subscription groupName: {} not exist", groupName);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/69361f60/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
index 6f2c9a3..f596b83 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
@@ -53,8 +53,9 @@ public class MQClientManager {
             MQClientInstance prev = this.factoryTable.putIfAbsent(clientId, instance);
             if (prev != null) {
                 instance = prev;
+                log.warn("Returned Previous MQClientInstance for clientId:[{}]", clientId);
             } else {
-                log.warn("Previous MQClientInstance has created for clientId:[{}]", clientId);
+                log.info("Created new MQClientInstance for clientId:[{}]", clientId);
             }
         }
 


[04/13] incubator-rocketmq git commit: [ROCKETMQ-64] Remove duplication code line in BrokerOuterAPI.registerBroker method, thanks @naughtybear, closes apache/incubator-rocketmq#44

Posted by st...@apache.org.
[ROCKETMQ-64] Remove duplication code line in BrokerOuterAPI.registerBroker method, thanks @naughtybear, closes apache/incubator-rocketmq#44


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/581039be
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/581039be
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/581039be

Branch: refs/heads/ROCKETMQ-57
Commit: 581039bef2b6a628ec1611f24880b87d8a8d6fd7
Parents: 457bb61
Author: yukon <yu...@apache.org>
Authored: Fri Jan 20 11:23:31 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Fri Jan 20 11:23:31 2017 +0800

----------------------------------------------------------------------
 .../main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java    | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/581039be/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
index 8726c69..039c942 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
@@ -173,7 +173,6 @@ public class BrokerOuterAPI {
                 RegisterBrokerResult result = new RegisterBrokerResult();
                 result.setMasterAddr(responseHeader.getMasterAddr());
                 result.setHaServerAddr(responseHeader.getHaServerAddr());
-                result.setHaServerAddr(responseHeader.getHaServerAddr());
                 if (response.getBody() != null) {
                     result.setKvTable(KVTable.decode(response.getBody(), KVTable.class));
                 }


[13/13] incubator-rocketmq git commit: Merge branch 'master' into ROCKETMQ-57

Posted by st...@apache.org.
Merge branch 'master' into ROCKETMQ-57


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/63de56c7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/63de56c7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/63de56c7

Branch: refs/heads/ROCKETMQ-57
Commit: 63de56c7b6cada18338bb4be5e84fb17a379e5ac
Parents: f8d881b b4108d2
Author: stevenschew <st...@apache.org>
Authored: Fri Jan 20 14:55:52 2017 +0800
Committer: stevenschew <st...@apache.org>
Committed: Fri Jan 20 14:55:52 2017 +0800

----------------------------------------------------------------------
 .travis.yml                                     |   1 +
 BUILDING                                        |   2 +-
 .../rocketmq/broker/out/BrokerOuterAPI.java     |   1 -
 .../subscription/SubscriptionGroupManager.java  |   2 +-
 .../rocketmq/client/impl/MQClientManager.java   |   3 +-
 .../processor/DefaultRequestProcessorTest.java  | 246 +++++++++++++++
 pom.xml                                         |  73 +++--
 .../remoting/protocol/RemotingSerializable.java |   2 +-
 .../remoting/protocol/RocketMQSerializable.java |  17 +-
 style/rmq_checkstyle.xml                        |   1 -
 test/pom.xml                                    |  52 ++++
 .../test/client/mq/MQAsyncProducer.java         |  85 ++++++
 .../test/client/rmq/RMQAsyncSendProducer.java   | 226 ++++++++++++++
 .../test/client/rmq/RMQBroadCastConsumer.java   |  37 +++
 .../test/client/rmq/RMQNormalConsumer.java      |  90 ++++++
 .../test/client/rmq/RMQNormalProducer.java      | 167 ++++++++++
 .../clientinterface/AbstractMQConsumer.java     | 112 +++++++
 .../clientinterface/AbstractMQProducer.java     | 151 +++++++++
 .../test/clientinterface/MQCollector.java       | 108 +++++++
 .../test/clientinterface/MQConsumer.java        |  26 ++
 .../test/clientinterface/MQProducer.java        |  30 ++
 .../rocketmq/test/factory/ConsumerFactory.java  |  45 +++
 .../rocketmq/test/factory/MQMessageFactory.java | 128 ++++++++
 .../rocketmq/test/factory/MessageFactory.java   |  62 ++++
 .../rocketmq/test/factory/ProducerFactory.java  |  37 +++
 .../test/factory/SendCallBackFactory.java       |  35 +++
 .../rocketmq/test/factory/TagMessage.java       | 108 +++++++
 .../test/listener/AbstractListener.java         | 104 +++++++
 .../rmq/concurrent/RMQDelayListner.java         |  61 ++++
 .../rmq/concurrent/RMQNormalListner.java        |  70 +++++
 .../listener/rmq/order/RMQOrderListener.java    |  85 ++++++
 .../rocketmq/test/message/MessageQueueMsg.java  |  62 ++++
 .../rocketmq/test/sendresult/SendResult.java    |  62 ++++
 .../apache/rocketmq/test/util/Condition.java    |  23 ++
 .../test/util/DuplicateMessageInfo.java         | 137 +++++++++
 .../org/apache/rocketmq/test/util/FileUtil.java | 108 +++++++
 .../org/apache/rocketmq/test/util/MQAdmin.java  | 164 ++++++++++
 .../rocketmq/test/util/MQRandomUtils.java       |  28 ++
 .../org/apache/rocketmq/test/util/MQWait.java   |  93 ++++++
 .../apache/rocketmq/test/util/RandomUtil.java   | 306 +++++++++++++++++++
 .../apache/rocketmq/test/util/RandomUtils.java  |  91 ++++++
 .../org/apache/rocketmq/test/util/TestUtil.java | 122 ++++++++
 .../apache/rocketmq/test/util/TestUtils.java    |  50 +++
 .../apache/rocketmq/test/util/VerifyUtils.java  | 146 +++++++++
 .../test/util/data/collect/DataCollector.java   |  45 +++
 .../util/data/collect/DataCollectorManager.java | 112 +++++++
 .../test/util/data/collect/DataFilter.java      |  22 ++
 .../collect/impl/ListDataCollectorImpl.java     |  95 ++++++
 .../data/collect/impl/MapDataCollectorImpl.java | 111 +++++++
 .../test/util/parallel/ParallelTask.java        |  43 +++
 .../util/parallel/ParallelTaskExecutor.java     |  67 ++++
 .../rocketmq/test/util/parallel/Task4Test.java  |  30 ++
 .../org/apache/rocketmq/test/base/BaseConf.java | 162 ++++++++++
 .../rocketmq/test/base/IntegrationTestBase.java | 143 +++++++++
 .../balance/NormalMsgDynamicBalanceIT.java      | 111 +++++++
 .../balance/NormalMsgStaticBalanceIT.java       | 109 +++++++
 .../consumer/broadcast/BaseBroadCastIT.java     |  56 ++++
 .../normal/BroadCastNormalMsgNotRecvIT.java     |  73 +++++
 .../normal/BroadCastNormalMsgRecvCrashIT.java   |  90 ++++++
 .../normal/BroadCastNormalMsgRecvFailIT.java    |  72 +++++
 .../BroadCastNormalMsgRecvStartLaterIT.java     |  88 ++++++
 .../BroadCastNormalMsgTwoDiffGroupRecvIT.java   |  78 +++++
 .../normal/NormalMsgTwoSameGroupConsumerIT.java |  78 +++++
 .../broadcast/order/OrderMsgBroadCastIT.java    |  75 +++++
 .../tag/BroadCastTwoConsumerFilterIT.java       |  78 +++++
 .../tag/BroadCastTwoConsumerSubDiffTagIT.java   |  75 +++++
 .../tag/BroadCastTwoConsumerSubTagIT.java       |  75 +++++
 .../consumer/cluster/DynamicAddAndCrashIT.java  | 103 +++++++
 .../consumer/cluster/DynamicAddConsumerIT.java  |  97 ++++++
 .../cluster/DynamicCrashConsumerIT.java         | 100 ++++++
 .../test/client/consumer/tag/MulTagSubIT.java   | 156 ++++++++++
 .../consumer/tag/TagMessageWith1ConsumerIT.java | 197 ++++++++++++
 .../tag/TagMessageWithMulConsumerIT.java        | 196 ++++++++++++
 .../tag/TagMessageWithSameGroupConsumerIT.java  | 115 +++++++
 .../consumer/topic/MulConsumerMulTopicIT.java   | 108 +++++++
 .../consumer/topic/OneConsumerMulTopicIT.java   | 104 +++++++
 .../producer/async/AsyncSendExceptionIT.java    | 150 +++++++++
 .../async/AsyncSendWithMessageQueueIT.java      |  85 ++++++
 .../AsyncSendWithMessageQueueSelectorIT.java    | 106 +++++++
 .../async/AsyncSendWithOnlySendCallBackIT.java  |  64 ++++
 .../producer/exception/msg/ChinaPropIT.java     |  74 +++++
 .../exception/msg/MessageExceptionIT.java       | 129 ++++++++
 .../exception/msg/MessageUserPropIT.java        |  94 ++++++
 .../ProducerGroupAndInstanceNameValidityIT.java |  69 +++++
 .../producer/oneway/OneWaySendExceptionIT.java  |  78 +++++
 .../client/producer/oneway/OneWaySendIT.java    |  64 ++++
 .../producer/oneway/OneWaySendWithMQIT.java     |  79 +++++
 .../oneway/OneWaySendWithSelectorIT.java        | 104 +++++++
 .../order/OrderMsgDynamicRebalanceIT.java       | 115 +++++++
 .../test/client/producer/order/OrderMsgIT.java  | 108 +++++++
 .../producer/order/OrderMsgRebalanceIT.java     | 133 ++++++++
 .../producer/order/OrderMsgWithTagIT.java       | 169 ++++++++++
 .../querymsg/QueryMsgByIdExceptionIT.java       |  81 +++++
 .../producer/querymsg/QueryMsgByIdIT.java       |  75 +++++
 .../producer/querymsg/QueryMsgByKeyIT.java      | 104 +++++++
 .../apache/rocketmq/test/delay/DelayConf.java   |  27 ++
 .../rocketmq/test/delay/NormalMsgDelayIT.java   | 116 +++++++
 .../test/smoke/NormalMessageSendAndRecvIT.java  |  62 ++++
 test/src/test/resources/log4j.xml               |  46 +++
 test/src/test/resources/logback-test.xml        |  33 ++
 100 files changed, 8750 insertions(+), 38 deletions(-)
----------------------------------------------------------------------



[10/13] incubator-rocketmq git commit: [ROCKETMQ-42] Closes apache/incubator-rocketmq#35, closes apache/incubator-rocketmq#41, *Won't fix*

Posted by st...@apache.org.
[ROCKETMQ-42] Closes apache/incubator-rocketmq#35, closes apache/incubator-rocketmq#41, *Won't fix*


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/0661ac8c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/0661ac8c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/0661ac8c

Branch: refs/heads/ROCKETMQ-57
Commit: 0661ac8c07a995058b5f33579867779e4d487ee1
Parents: 788771a
Author: yukon <yu...@apache.org>
Authored: Fri Jan 20 13:51:52 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Fri Jan 20 13:51:52 2017 +0800

----------------------------------------------------------------------

----------------------------------------------------------------------



[03/13] incubator-rocketmq git commit: [ROCKETMQ-59] Change Charset usages in RocketMQSerializable to RocketMQSerializable#CHARSET_UTF8, closes apache/incubator-rocketmq#43

Posted by st...@apache.org.
[ROCKETMQ-59] Change Charset usages in RocketMQSerializable to RocketMQSerializable#CHARSET_UTF8, closes apache/incubator-rocketmq#43


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/457bb61f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/457bb61f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/457bb61f

Branch: refs/heads/ROCKETMQ-57
Commit: 457bb61f0489d58c810330b40c62ccb7e75b602b
Parents: 62d811e
Author: iskl <sh...@kailai.me>
Authored: Fri Jan 20 11:18:42 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Fri Jan 20 11:18:42 2017 +0800

----------------------------------------------------------------------
 .../remoting/protocol/RemotingSerializable.java    |  2 +-
 .../remoting/protocol/RocketMQSerializable.java    | 17 ++++++++---------
 2 files changed, 9 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/457bb61f/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
index a9c0a62..f80ff14 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
@@ -20,7 +20,7 @@ import com.alibaba.fastjson.JSON;
 import java.nio.charset.Charset;
 
 public abstract class RemotingSerializable {
-    public final static Charset CHARSET_UTF8 = Charset.forName("UTF-8");
+    private final static Charset CHARSET_UTF8 = Charset.forName("UTF-8");
 
     public static byte[] encode(final Object obj) {
         final String json = toJson(obj, false);

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/457bb61f/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java
index 0ebe795..86dab46 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java
@@ -23,14 +23,14 @@ import java.util.Iterator;
 import java.util.Map;
 
 public class RocketMQSerializable {
-    public static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
+    private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
 
     public static byte[] rocketMQProtocolEncode(RemotingCommand cmd) {
         // String remark
         byte[] remarkBytes = null;
         int remarkLen = 0;
         if (cmd.getRemark() != null && cmd.getRemark().length() > 0) {
-            remarkBytes = cmd.getRemark().getBytes(RemotingSerializable.CHARSET_UTF8);
+            remarkBytes = cmd.getRemark().getBytes(CHARSET_UTF8);
             remarkLen = remarkBytes.length;
         }
 
@@ -89,9 +89,9 @@ public class RocketMQSerializable {
             if (entry.getKey() != null && entry.getValue() != null) {
                 kvLength =
                     // keySize + Key
-                    2 + entry.getKey().getBytes(RemotingSerializable.CHARSET_UTF8).length
+                    2 + entry.getKey().getBytes(CHARSET_UTF8).length
                         // valSize + val
-                        + 4 + entry.getValue().getBytes(RemotingSerializable.CHARSET_UTF8).length;
+                        + 4 + entry.getValue().getBytes(CHARSET_UTF8).length;
                 totalLength += kvLength;
             }
         }
@@ -103,8 +103,8 @@ public class RocketMQSerializable {
         while (it.hasNext()) {
             Map.Entry<String, String> entry = it.next();
             if (entry.getKey() != null && entry.getValue() != null) {
-                key = entry.getKey().getBytes(RemotingSerializable.CHARSET_UTF8);
-                val = entry.getValue().getBytes(RemotingSerializable.CHARSET_UTF8);
+                key = entry.getKey().getBytes(CHARSET_UTF8);
+                val = entry.getValue().getBytes(CHARSET_UTF8);
 
                 content.putShort((short) key.length);
                 content.put(key);
@@ -154,7 +154,7 @@ public class RocketMQSerializable {
         if (remarkLength > 0) {
             byte[] remarkContent = new byte[remarkLength];
             headerBuffer.get(remarkContent);
-            cmd.setRemark(new String(remarkContent, RemotingSerializable.CHARSET_UTF8));
+            cmd.setRemark(new String(remarkContent, CHARSET_UTF8));
         }
 
         // HashMap<String, String> extFields
@@ -187,8 +187,7 @@ public class RocketMQSerializable {
             valContent = new byte[valSize];
             byteBuffer.get(valContent);
 
-            map.put(new String(keyContent, RemotingSerializable.CHARSET_UTF8), new String(valContent,
-                RemotingSerializable.CHARSET_UTF8));
+            map.put(new String(keyContent, CHARSET_UTF8), new String(valContent, CHARSET_UTF8));
         }
         return map;
     }


[02/13] incubator-rocketmq git commit: [ROCKETMQ-43] Remove NoWhitespaceBefore module in rmq_checkstyle.xml, closes apache/incubator-rocketmq#36

Posted by st...@apache.org.
[ROCKETMQ-43] Remove NoWhitespaceBefore module in rmq_checkstyle.xml, closes apache/incubator-rocketmq#36


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/62d811e3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/62d811e3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/62d811e3

Branch: refs/heads/ROCKETMQ-57
Commit: 62d811e354c937327fcad0cb9399fcc5dc322b94
Parents: 69361f6
Author: wu-sheng <wu...@foxmail.com>
Authored: Fri Jan 20 11:05:24 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Fri Jan 20 11:05:24 2017 +0800

----------------------------------------------------------------------
 style/rmq_checkstyle.xml | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/62d811e3/style/rmq_checkstyle.xml
----------------------------------------------------------------------
diff --git a/style/rmq_checkstyle.xml b/style/rmq_checkstyle.xml
index 776b305..2872eb7 100644
--- a/style/rmq_checkstyle.xml
+++ b/style/rmq_checkstyle.xml
@@ -121,7 +121,6 @@
         <!--whitespace-->
         <module name="GenericWhitespace"/>
         <module name="NoWhitespaceBefore"/>
-        <module name="WhitespaceAfter"/>
         <module name="NoWhitespaceAfter"/>
         <module name="WhitespaceAround">
             <property name="allowEmptyConstructors" value="true"/>


[11/13] incubator-rocketmq git commit: [ROCKETMQ-54] Add test cases for DefaultRequestProcessor in namesrv module, closes apache/incubator-rocketmq#45

Posted by st...@apache.org.
[ROCKETMQ-54] Add test cases for DefaultRequestProcessor in namesrv module, closes apache/incubator-rocketmq#45


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/b4108d2d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/b4108d2d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/b4108d2d

Branch: refs/heads/ROCKETMQ-57
Commit: b4108d2d9d3b1522e45ac5e7ea37106f2135bfa0
Parents: 0661ac8
Author: iskl <sh...@kailai.me>
Authored: Fri Jan 20 13:57:59 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Fri Jan 20 13:57:59 2017 +0800

----------------------------------------------------------------------
 .../processor/DefaultRequestProcessorTest.java  | 246 +++++++++++++++++++
 1 file changed, 246 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/b4108d2d/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java
----------------------------------------------------------------------
diff --git a/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java
new file mode 100644
index 0000000..861e284
--- /dev/null
+++ b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java
@@ -0,0 +1,246 @@
+/*
+ * 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.rocketmq.namesrv.processor;
+
+import io.netty.channel.ChannelHandlerContext;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.rocketmq.common.namesrv.NamesrvConfig;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.header.namesrv.DeleteKVConfigRequestHeader;
+import org.apache.rocketmq.common.protocol.header.namesrv.GetKVConfigRequestHeader;
+import org.apache.rocketmq.common.protocol.header.namesrv.GetKVConfigResponseHeader;
+import org.apache.rocketmq.common.protocol.header.namesrv.PutKVConfigRequestHeader;
+import org.apache.rocketmq.common.protocol.header.namesrv.RegisterBrokerRequestHeader;
+import org.apache.rocketmq.common.protocol.route.BrokerData;
+import org.apache.rocketmq.namesrv.NamesrvController;
+import org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.assertj.core.util.Maps;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+public class DefaultRequestProcessorTest {
+    /** Test Target */
+    private DefaultRequestProcessor defaultRequestProcessor;
+
+    private NamesrvController       namesrvController;
+
+    private NamesrvConfig           namesrvConfig;
+
+    private NettyServerConfig       nettyServerConfig;
+
+    private Logger                  logger;
+
+    @Before
+    public void init() throws Exception {
+        namesrvConfig = new NamesrvConfig();
+        nettyServerConfig = new NettyServerConfig();
+
+        namesrvController = new NamesrvController(namesrvConfig, nettyServerConfig);
+        defaultRequestProcessor = new DefaultRequestProcessor(namesrvController);
+
+        logger = mock(Logger.class);
+        when(logger.isInfoEnabled()).thenReturn(false);
+        setFinalStatic(DefaultRequestProcessor.class.getDeclaredField("log"), logger);
+    }
+
+    @Test
+    public void testProcessRequest_PutKVConfig() throws RemotingCommandException {
+        PutKVConfigRequestHeader header = new PutKVConfigRequestHeader();
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.PUT_KV_CONFIG,
+            header);
+        request.addExtField("namespace", "namespace");
+        request.addExtField("key", "key");
+        request.addExtField("value", "value");
+
+        RemotingCommand response = defaultRequestProcessor.processRequest(null, request);
+
+        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
+        assertThat(response.getRemark()).isNull();
+
+        assertThat(namesrvController.getKvConfigManager().getKVConfig("namespace", "key"))
+            .isEqualTo("value");
+    }
+
+    @Test
+    public void testProcessRequest_GetKVConfigReturnNotNull() throws RemotingCommandException {
+        namesrvController.getKvConfigManager().putKVConfig("namespace", "key", "value");
+
+        GetKVConfigRequestHeader header = new GetKVConfigRequestHeader();
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_KV_CONFIG,
+            header);
+        request.addExtField("namespace", "namespace");
+        request.addExtField("key", "key");
+
+        RemotingCommand response = defaultRequestProcessor.processRequest(null, request);
+
+        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
+        assertThat(response.getRemark()).isNull();
+
+        GetKVConfigResponseHeader responseHeader = (GetKVConfigResponseHeader) response
+            .readCustomHeader();
+
+        assertThat(responseHeader.getValue()).isEqualTo("value");
+    }
+
+    @Test
+    public void testProcessRequest_GetKVConfigReturnNull() throws RemotingCommandException {
+        GetKVConfigRequestHeader header = new GetKVConfigRequestHeader();
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_KV_CONFIG,
+            header);
+        request.addExtField("namespace", "namespace");
+        request.addExtField("key", "key");
+
+        RemotingCommand response = defaultRequestProcessor.processRequest(null, request);
+
+        assertThat(response.getCode()).isEqualTo(ResponseCode.QUERY_NOT_FOUND);
+        assertThat(response.getRemark()).isEqualTo("No config item, Namespace: namespace Key: key");
+
+        GetKVConfigResponseHeader responseHeader = (GetKVConfigResponseHeader) response
+            .readCustomHeader();
+
+        assertThat(responseHeader.getValue()).isNull();
+    }
+
+    @Test
+    public void testProcessRequest_DeleteKVConfig() throws RemotingCommandException {
+        namesrvController.getKvConfigManager().putKVConfig("namespace", "key", "value");
+
+        DeleteKVConfigRequestHeader header = new DeleteKVConfigRequestHeader();
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.DELETE_KV_CONFIG,
+            header);
+        request.addExtField("namespace", "namespace");
+        request.addExtField("key", "key");
+
+        RemotingCommand response = defaultRequestProcessor.processRequest(null, request);
+
+        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
+        assertThat(response.getRemark()).isNull();
+
+        assertThat(namesrvController.getKvConfigManager().getKVConfig("namespace", "key"))
+            .isNull();
+    }
+
+    @Test
+    public void testProcessRequest_RegisterBroker() throws RemotingCommandException,
+                                                    NoSuchFieldException, IllegalAccessException {
+        RemotingCommand request = genSampleRegisterCmd(true);
+
+        ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
+        when(ctx.channel()).thenReturn(null);
+
+        RemotingCommand response = defaultRequestProcessor.processRequest(ctx, request);
+
+        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
+        assertThat(response.getRemark()).isNull();
+
+        RouteInfoManager routes = namesrvController.getRouteInfoManager();
+        Field brokerAddrTable = RouteInfoManager.class.getDeclaredField("brokerAddrTable");
+        brokerAddrTable.setAccessible(true);
+
+        BrokerData broker = new BrokerData();
+        broker.setBrokerName("broker");
+        broker.setBrokerAddrs((HashMap) Maps.newHashMap(new Long(2333), "10.10.1.1"));
+
+        assertThat((Map) brokerAddrTable.get(routes))
+            .contains(new HashMap.SimpleEntry("broker", broker));
+    }
+
+    @Test
+    public void testProcessRequest_RegisterBrokerWithFilterServer() throws RemotingCommandException,
+        NoSuchFieldException, IllegalAccessException {
+        RemotingCommand request = genSampleRegisterCmd(true);
+
+        // version >= MQVersion.Version.V3_0_11.ordinal() to register with filter server
+        request.setVersion(100); 
+
+        ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
+        when(ctx.channel()).thenReturn(null);
+
+        RemotingCommand response = defaultRequestProcessor.processRequest(ctx, request);
+
+        assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
+        assertThat(response.getRemark()).isNull();
+
+        RouteInfoManager routes = namesrvController.getRouteInfoManager();
+        Field brokerAddrTable = RouteInfoManager.class.getDeclaredField("brokerAddrTable");
+        brokerAddrTable.setAccessible(true);
+
+        BrokerData broker = new BrokerData();
+        broker.setBrokerName("broker");
+        broker.setBrokerAddrs((HashMap) Maps.newHashMap(new Long(2333), "10.10.1.1"));
+
+        assertThat((Map) brokerAddrTable.get(routes))
+            .contains(new HashMap.SimpleEntry("broker", broker));
+    }
+
+    @Test
+    public void testProcessRequest_UnregisterBroker() throws RemotingCommandException, NoSuchFieldException, IllegalAccessException {
+        ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
+        when(ctx.channel()).thenReturn(null);
+
+        //Register broker
+        RemotingCommand regRequest = genSampleRegisterCmd(true);
+        defaultRequestProcessor.processRequest(ctx, regRequest);
+
+        //Unregister broker
+        RemotingCommand unregRequest = genSampleRegisterCmd(false);
+        RemotingCommand unregResponse = defaultRequestProcessor.processRequest(ctx, unregRequest);
+
+        assertThat(unregResponse.getCode()).isEqualTo(ResponseCode.SUCCESS);
+        assertThat(unregResponse.getRemark()).isNull();
+
+        RouteInfoManager routes = namesrvController.getRouteInfoManager();
+        Field brokerAddrTable = RouteInfoManager.class.getDeclaredField("brokerAddrTable");
+        brokerAddrTable.setAccessible(true);
+
+        assertThat((Map)brokerAddrTable.get(routes)).isEmpty();
+    }
+
+
+    private static RemotingCommand genSampleRegisterCmd(boolean reg) {
+        RegisterBrokerRequestHeader header = new RegisterBrokerRequestHeader();
+        header.setBrokerName("broker");
+        RemotingCommand request = RemotingCommand.createRequestCommand(
+            reg ? RequestCode.REGISTER_BROKER : RequestCode.UNREGISTER_BROKER, header);
+        request.addExtField("brokerName", "broker");
+        request.addExtField("brokerAddr", "10.10.1.1");
+        request.addExtField("clusterName", "cluster");
+        request.addExtField("haServerAddr", "10.10.2.1");
+        request.addExtField("brokerId", "2333");
+        return request;
+    }
+
+
+    private static void setFinalStatic(Field field, Object newValue) throws Exception {
+        field.setAccessible(true);
+        Field modifiersField = Field.class.getDeclaredField("modifiers");
+        modifiersField.setAccessible(true);
+        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+        field.set(null, newValue);
+    }
+}
\ No newline at end of file


[09/13] incubator-rocketmq git commit: [RocketMQ-58] Add integration test for RocketMQ, also thanks @fenglianghfl for this commit, closes apache/incubator-rocketmq#46

Posted by st...@apache.org.
[RocketMQ-58] Add integration test for RocketMQ, also thanks @fenglianghfl for this commit, closes apache/incubator-rocketmq#46


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/788771a8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/788771a8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/788771a8

Branch: refs/heads/ROCKETMQ-57
Commit: 788771a851512f1e588ebeb6952e61fe8d892804
Parents: 581039b
Author: dongeforever <zh...@yeah.net>
Authored: Fri Jan 20 11:36:31 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Fri Jan 20 11:36:31 2017 +0800

----------------------------------------------------------------------
 .travis.yml                                     |   1 +
 BUILDING                                        |   2 +-
 pom.xml                                         |  73 +++--
 test/pom.xml                                    |  52 ++++
 .../test/client/mq/MQAsyncProducer.java         |  85 ++++++
 .../test/client/rmq/RMQAsyncSendProducer.java   | 226 ++++++++++++++
 .../test/client/rmq/RMQBroadCastConsumer.java   |  37 +++
 .../test/client/rmq/RMQNormalConsumer.java      |  90 ++++++
 .../test/client/rmq/RMQNormalProducer.java      | 167 ++++++++++
 .../clientinterface/AbstractMQConsumer.java     | 112 +++++++
 .../clientinterface/AbstractMQProducer.java     | 151 +++++++++
 .../test/clientinterface/MQCollector.java       | 108 +++++++
 .../test/clientinterface/MQConsumer.java        |  26 ++
 .../test/clientinterface/MQProducer.java        |  30 ++
 .../rocketmq/test/factory/ConsumerFactory.java  |  45 +++
 .../rocketmq/test/factory/MQMessageFactory.java | 128 ++++++++
 .../rocketmq/test/factory/MessageFactory.java   |  62 ++++
 .../rocketmq/test/factory/ProducerFactory.java  |  37 +++
 .../test/factory/SendCallBackFactory.java       |  35 +++
 .../rocketmq/test/factory/TagMessage.java       | 108 +++++++
 .../test/listener/AbstractListener.java         | 104 +++++++
 .../rmq/concurrent/RMQDelayListner.java         |  61 ++++
 .../rmq/concurrent/RMQNormalListner.java        |  70 +++++
 .../listener/rmq/order/RMQOrderListener.java    |  85 ++++++
 .../rocketmq/test/message/MessageQueueMsg.java  |  62 ++++
 .../rocketmq/test/sendresult/SendResult.java    |  62 ++++
 .../apache/rocketmq/test/util/Condition.java    |  23 ++
 .../test/util/DuplicateMessageInfo.java         | 137 +++++++++
 .../org/apache/rocketmq/test/util/FileUtil.java | 108 +++++++
 .../org/apache/rocketmq/test/util/MQAdmin.java  | 164 ++++++++++
 .../rocketmq/test/util/MQRandomUtils.java       |  28 ++
 .../org/apache/rocketmq/test/util/MQWait.java   |  93 ++++++
 .../apache/rocketmq/test/util/RandomUtil.java   | 306 +++++++++++++++++++
 .../apache/rocketmq/test/util/RandomUtils.java  |  91 ++++++
 .../org/apache/rocketmq/test/util/TestUtil.java | 122 ++++++++
 .../apache/rocketmq/test/util/TestUtils.java    |  50 +++
 .../apache/rocketmq/test/util/VerifyUtils.java  | 146 +++++++++
 .../test/util/data/collect/DataCollector.java   |  45 +++
 .../util/data/collect/DataCollectorManager.java | 112 +++++++
 .../test/util/data/collect/DataFilter.java      |  22 ++
 .../collect/impl/ListDataCollectorImpl.java     |  95 ++++++
 .../data/collect/impl/MapDataCollectorImpl.java | 111 +++++++
 .../test/util/parallel/ParallelTask.java        |  43 +++
 .../util/parallel/ParallelTaskExecutor.java     |  67 ++++
 .../rocketmq/test/util/parallel/Task4Test.java  |  30 ++
 .../org/apache/rocketmq/test/base/BaseConf.java | 162 ++++++++++
 .../rocketmq/test/base/IntegrationTestBase.java | 143 +++++++++
 .../balance/NormalMsgDynamicBalanceIT.java      | 111 +++++++
 .../balance/NormalMsgStaticBalanceIT.java       | 109 +++++++
 .../consumer/broadcast/BaseBroadCastIT.java     |  56 ++++
 .../normal/BroadCastNormalMsgNotRecvIT.java     |  73 +++++
 .../normal/BroadCastNormalMsgRecvCrashIT.java   |  90 ++++++
 .../normal/BroadCastNormalMsgRecvFailIT.java    |  72 +++++
 .../BroadCastNormalMsgRecvStartLaterIT.java     |  88 ++++++
 .../BroadCastNormalMsgTwoDiffGroupRecvIT.java   |  78 +++++
 .../normal/NormalMsgTwoSameGroupConsumerIT.java |  78 +++++
 .../broadcast/order/OrderMsgBroadCastIT.java    |  75 +++++
 .../tag/BroadCastTwoConsumerFilterIT.java       |  78 +++++
 .../tag/BroadCastTwoConsumerSubDiffTagIT.java   |  75 +++++
 .../tag/BroadCastTwoConsumerSubTagIT.java       |  75 +++++
 .../consumer/cluster/DynamicAddAndCrashIT.java  | 103 +++++++
 .../consumer/cluster/DynamicAddConsumerIT.java  |  97 ++++++
 .../cluster/DynamicCrashConsumerIT.java         | 100 ++++++
 .../test/client/consumer/tag/MulTagSubIT.java   | 156 ++++++++++
 .../consumer/tag/TagMessageWith1ConsumerIT.java | 197 ++++++++++++
 .../tag/TagMessageWithMulConsumerIT.java        | 196 ++++++++++++
 .../tag/TagMessageWithSameGroupConsumerIT.java  | 115 +++++++
 .../consumer/topic/MulConsumerMulTopicIT.java   | 108 +++++++
 .../consumer/topic/OneConsumerMulTopicIT.java   | 104 +++++++
 .../producer/async/AsyncSendExceptionIT.java    | 150 +++++++++
 .../async/AsyncSendWithMessageQueueIT.java      |  85 ++++++
 .../AsyncSendWithMessageQueueSelectorIT.java    | 106 +++++++
 .../async/AsyncSendWithOnlySendCallBackIT.java  |  64 ++++
 .../producer/exception/msg/ChinaPropIT.java     |  74 +++++
 .../exception/msg/MessageExceptionIT.java       | 129 ++++++++
 .../exception/msg/MessageUserPropIT.java        |  94 ++++++
 .../ProducerGroupAndInstanceNameValidityIT.java |  69 +++++
 .../producer/oneway/OneWaySendExceptionIT.java  |  78 +++++
 .../client/producer/oneway/OneWaySendIT.java    |  64 ++++
 .../producer/oneway/OneWaySendWithMQIT.java     |  79 +++++
 .../oneway/OneWaySendWithSelectorIT.java        | 104 +++++++
 .../order/OrderMsgDynamicRebalanceIT.java       | 115 +++++++
 .../test/client/producer/order/OrderMsgIT.java  | 108 +++++++
 .../producer/order/OrderMsgRebalanceIT.java     | 133 ++++++++
 .../producer/order/OrderMsgWithTagIT.java       | 169 ++++++++++
 .../querymsg/QueryMsgByIdExceptionIT.java       |  81 +++++
 .../producer/querymsg/QueryMsgByIdIT.java       |  75 +++++
 .../producer/querymsg/QueryMsgByKeyIT.java      | 104 +++++++
 .../apache/rocketmq/test/delay/DelayConf.java   |  27 ++
 .../rocketmq/test/delay/NormalMsgDelayIT.java   | 116 +++++++
 .../test/smoke/NormalMessageSendAndRecvIT.java  |  62 ++++
 test/src/test/resources/log4j.xml               |  46 +++
 test/src/test/resources/logback-test.xml        |  33 ++
 93 files changed, 8492 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index dd57ba3..916cac5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,4 +39,5 @@ script:
   - travis_retry mvn -B package jacoco:report coveralls:report
 
 after_success:
+  - mvn clean install -Pit-test
   - mvn sonar:sonar

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/BUILDING
----------------------------------------------------------------------
diff --git a/BUILDING b/BUILDING
index a92cbd5..1498b3e 100644
--- a/BUILDING
+++ b/BUILDING
@@ -34,4 +34,4 @@ Then, import to eclipse by specifying the root directory of the project via:
 
 Execute the following command in order to build the tar.gz packages and install JAR to the local repository:
 
-$ mvn clean package install -Prelease-all assembly:assembly -U
\ No newline at end of file
+$ mvn clean install -Prelease-all assembly:assembly -U
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 8ec8170..8b8c468 100644
--- a/pom.xml
+++ b/pom.xml
@@ -160,9 +160,6 @@
         <!-- Compiler settings properties -->
         <maven.compiler.source>1.7</maven.compiler.source>
         <maven.compiler.target>1.7</maven.compiler.target>
-
-        <!-- Overwritten by the test configuration,otherwise the JaCoCo agent cannot be attached.Details see http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html -->
-        <argLine>-Xms512m -Xmx1024m</argLine>
         <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
         <!-- URL of the ASF SonarQube server -->
         <sonar.host.url>https://builds.apache.org/analysis</sonar.host.url>
@@ -181,6 +178,7 @@
         <module>example</module>
         <module>filtersrv</module>
         <module>srvutil</module>
+        <module>test</module>
     </modules>
 
     <build>
@@ -237,25 +235,6 @@
                 </configuration>
             </plugin>
             <plugin>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.19.1</version>
-                <configuration>
-                    <forkCount>1</forkCount>
-                    <reuseForks>true</reuseForks>
-                    <includes>
-                        <include>**/*Test.java</include>
-                    </includes>
-                </configuration>
-            </plugin>
-            <plugin>
-                <artifactId>maven-failsafe-plugin</artifactId>
-                <version>2.19.1</version>
-                <configuration>
-                    <forkCount>1</forkCount>
-                    <reuseForks>true</reuseForks>
-                </configuration>
-            </plugin>
-            <plugin>
                 <artifactId>maven-javadoc-plugin</artifactId>
                 <version>2.10.4</version>
                 <configuration>
@@ -310,6 +289,7 @@
                             <encoding>UTF-8</encoding>
                             <consoleOutput>true</consoleOutput>
                             <failsOnError>true</failsOnError>
+                            <includeTestSourceDirectory>false</includeTestSourceDirectory>
                         </configuration>
                         <goals>
                             <goal>check</goal>
@@ -352,12 +332,20 @@
                         <goals>
                             <goal>prepare-agent</goal>
                         </goals>
+                        <configuration>
+                            <destFile>${project.build.directory}/jacoco.exec</destFile>
+                        </configuration>
                     </execution>
                     <execution>
                         <id>default-prepare-agent-integration</id>
+                        <phase>pre-integration-test</phase>
                         <goals>
                             <goal>prepare-agent-integration</goal>
                         </goals>
+                        <configuration>
+                            <destFile>${project.build.directory}/jacoco-it.exec</destFile>
+                            <propertyName>failsafeArgLine</propertyName>
+                        </configuration>
                     </execution>
                     <execution>
                         <id>default-report</id>
@@ -374,6 +362,14 @@
                 </executions>
             </plugin>
             <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.19.1</version>
+                <configuration>
+                    <forkCount>1</forkCount>
+                    <reuseForks>true</reuseForks>
+                </configuration>
+            </plugin>
+            <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>findbugs-maven-plugin</artifactId>
                 <version>3.0.4</version>
@@ -475,6 +471,37 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>it-test</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <version>2.19.1</version>
+                        <configuration>
+                            <forkCount>1</forkCount>
+                            <reuseForks>true</reuseForks>
+                            <argLine>@{failsafeArgLine}</argLine>
+                            <excludes>
+                                <exclude>**/NormalMsgDelayIT.java</exclude>
+                                <exclude>**/BroadCastNormalMsgNotRecvIT.java</exclude>
+                                <exclude>**/TagMessageWithSameGroupConsumerIT.java</exclude>
+                                <exclude>**/AsyncSendWithMessageQueueSelectorIT.java</exclude>
+                                <exclude>**/AsyncSendWithMessageQueueIT.java</exclude>
+                            </excludes>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 
     <dependencies>
@@ -537,7 +564,7 @@
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
-                <artifactId>rocketmq-qatest</artifactId>
+                <artifactId>rocketmq-test</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/pom.xml
----------------------------------------------------------------------
diff --git a/test/pom.xml b/test/pom.xml
new file mode 100644
index 0000000..09ec9d3
--- /dev/null
+++ b/test/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rocketmq-all</artifactId>
+        <groupId>org.apache.rocketmq</groupId>
+        <version>4.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rocketmq-test</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-broker</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-namesrv</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.truth</groupId>
+            <artifactId>truth</artifactId>
+            <version>0.30</version>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/client/mq/MQAsyncProducer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/client/mq/MQAsyncProducer.java b/test/src/main/java/org/apache/rocketmq/test/client/mq/MQAsyncProducer.java
new file mode 100644
index 0000000..6b2357b
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/client/mq/MQAsyncProducer.java
@@ -0,0 +1,85 @@
+/*
+ * 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.rocketmq.test.client.mq;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.clientinterface.AbstractMQProducer;
+import org.apache.rocketmq.test.util.TestUtil;
+
+public class MQAsyncProducer {
+    private static Logger logger = Logger.getLogger(MQAsyncProducer.class);
+    private AbstractMQProducer producer = null;
+    private long msgNum;
+    private int intervalMills;
+    private Thread sendT;
+    private AtomicBoolean bPause = new AtomicBoolean(false);
+
+    public MQAsyncProducer(final AbstractMQProducer producer, final long msgNum,
+        final int intervalMills) {
+        this.producer = producer;
+        this.msgNum = msgNum;
+        this.intervalMills = intervalMills;
+
+        sendT = new Thread(new Runnable() {
+            public void run() {
+                for (int i = 0; i < msgNum; i++) {
+                    if (!bPause.get()) {
+                        producer.send();
+                        TestUtil.waitForMonment(intervalMills);
+                    } else {
+                        while (true) {
+                            if (bPause.get()) {
+                                TestUtil.waitForMonment(10);
+                            } else
+                                break;
+                        }
+                    }
+
+                }
+            }
+        });
+
+    }
+
+    public void start() {
+        sendT.start();
+    }
+
+    public void waitSendAll(int waitMills) {
+        long startTime = System.currentTimeMillis();
+        while ((producer.getAllMsgBody().size() + producer.getSendErrorMsg().size()) < msgNum) {
+            if (System.currentTimeMillis() - startTime < waitMills) {
+                TestUtil.waitForMonment(200);
+            } else {
+                logger.error(String.format("time elapse:%s, but the message sending has not finished",
+                    System.currentTimeMillis() - startTime));
+                break;
+            }
+        }
+    }
+
+    public void pauseProducer() {
+        bPause.set(true);
+    }
+
+    public void notifyProducer() {
+        bPause.set(false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQAsyncSendProducer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQAsyncSendProducer.java b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQAsyncSendProducer.java
new file mode 100644
index 0000000..4a2ce2b
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQAsyncSendProducer.java
@@ -0,0 +1,226 @@
+/*
+ * 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.rocketmq.test.client.rmq;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.MessageQueueSelector;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.clientinterface.AbstractMQProducer;
+import org.apache.rocketmq.test.sendresult.SendResult;
+import org.apache.rocketmq.test.util.RandomUtil;
+import org.apache.rocketmq.test.util.TestUtil;
+
+public class RMQAsyncSendProducer extends AbstractMQProducer {
+    private static Logger logger = Logger
+        .getLogger(RMQAsyncSendProducer.class);
+    private String nsAddr = null;
+    private DefaultMQProducer producer = null;
+    private SendCallback sendCallback = null;
+    private List<org.apache.rocketmq.client.producer.SendResult> successSendResult = new ArrayList<org.apache.rocketmq.client.producer.SendResult>();
+    private AtomicInteger exceptionMsgCount = new AtomicInteger(
+        0);
+    private int msgSize = 0;
+
+    public RMQAsyncSendProducer(String nsAddr, String topic) {
+        super(topic);
+        this.nsAddr = nsAddr;
+        sendCallback = new SendCallback() {
+            public void onSuccess(org.apache.rocketmq.client.producer.SendResult sendResult) {
+                successSendResult.add(sendResult);
+            }
+
+            public void onException(Throwable throwable) {
+                exceptionMsgCount.getAndIncrement();
+            }
+        };
+
+        create();
+        start();
+    }
+
+    public int getSuccessMsgCount() {
+        return successSendResult.size();
+    }
+
+    public List<org.apache.rocketmq.client.producer.SendResult> getSuccessSendResult() {
+        return successSendResult;
+    }
+
+    public int getExceptionMsgCount() {
+        return exceptionMsgCount.get();
+    }
+
+    private void create() {
+        producer = new DefaultMQProducer();
+        producer.setProducerGroup(RandomUtil.getStringByUUID());
+        producer.setInstanceName(RandomUtil.getStringByUUID());
+
+        if (nsAddr != null) {
+            producer.setNamesrvAddr(nsAddr);
+        }
+
+    }
+
+    private void start() {
+        try {
+            producer.start();
+        } catch (MQClientException e) {
+            logger.error("producer start failed!");
+            e.printStackTrace();
+        }
+    }
+
+    public SendResult send(Object msg, Object arg) {
+        return null;
+    }
+
+    public void shutdown() {
+        producer.shutdown();
+    }
+
+    public void asyncSend(Object msg) {
+        Message metaqMsg = (Message) msg;
+        try {
+            producer.send(metaqMsg, sendCallback);
+            msgBodys.addData(new String(metaqMsg.getBody()));
+            originMsgs.addData(msg);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void asyncSend(int msgSize) {
+        this.msgSize = msgSize;
+
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, RandomUtil.getStringByUUID().getBytes());
+            this.asyncSend(msg);
+        }
+    }
+
+    public void asyncSend(Object msg, MessageQueueSelector selector, Object arg) {
+        Message metaqMsg = (Message) msg;
+        try {
+            producer.send(metaqMsg, selector, arg, sendCallback);
+            msgBodys.addData(new String(metaqMsg.getBody()));
+            originMsgs.addData(msg);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void asyncSend(int msgSize, MessageQueueSelector selector) {
+        this.msgSize = msgSize;
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, RandomUtil.getStringByUUID().getBytes());
+            this.asyncSend(msg, selector, i);
+        }
+    }
+
+    public void asyncSend(Object msg, MessageQueue mq) {
+        Message metaqMsg = (Message) msg;
+        try {
+            producer.send(metaqMsg, mq, sendCallback);
+            msgBodys.addData(new String(metaqMsg.getBody()));
+            originMsgs.addData(msg);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void asyncSend(int msgSize, MessageQueue mq) {
+        this.msgSize = msgSize;
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, RandomUtil.getStringByUUID().getBytes());
+            this.asyncSend(msg, mq);
+        }
+    }
+
+    public void waitForResponse(int timeoutMills) {
+        long startTime = System.currentTimeMillis();
+        while (this.successSendResult.size() != this.msgSize) {
+            if (System.currentTimeMillis() - startTime < timeoutMills) {
+                TestUtil.waitForMonment(100);
+            } else {
+                logger.info("timeout but still not recv all response!");
+                break;
+            }
+        }
+    }
+
+    public void sendOneWay(Object msg) {
+        Message metaqMsg = (Message) msg;
+        try {
+            producer.sendOneway(metaqMsg);
+            msgBodys.addData(new String(metaqMsg.getBody()));
+            originMsgs.addData(msg);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void sendOneWay(int msgSize) {
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, RandomUtil.getStringByUUID().getBytes());
+            this.sendOneWay(msg);
+        }
+    }
+
+    public void sendOneWay(Object msg, MessageQueue mq) {
+        Message metaqMsg = (Message) msg;
+        try {
+            producer.sendOneway(metaqMsg, mq);
+            msgBodys.addData(new String(metaqMsg.getBody()));
+            originMsgs.addData(msg);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void sendOneWay(int msgSize, MessageQueue mq) {
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, RandomUtil.getStringByUUID().getBytes());
+            this.sendOneWay(msg, mq);
+        }
+    }
+
+    public void sendOneWay(Object msg, MessageQueueSelector selector, Object arg) {
+        Message metaqMsg = (Message) msg;
+        try {
+            producer.sendOneway(metaqMsg, selector, arg);
+            msgBodys.addData(new String(metaqMsg.getBody()));
+            originMsgs.addData(msg);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void sendOneWay(int msgSize, MessageQueueSelector selector) {
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, RandomUtil.getStringByUUID().getBytes());
+            this.sendOneWay(msg, selector, i);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQBroadCastConsumer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQBroadCastConsumer.java b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQBroadCastConsumer.java
new file mode 100644
index 0000000..8af49ea
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQBroadCastConsumer.java
@@ -0,0 +1,37 @@
+/*
+ * 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.rocketmq.test.client.rmq;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+public class RMQBroadCastConsumer extends RMQNormalConsumer {
+    private static Logger logger = Logger.getLogger(RMQBroadCastConsumer.class);
+
+    public RMQBroadCastConsumer(String nsAddr, String topic, String subExpression,
+        String consumerGroup, AbstractListener listner) {
+        super(nsAddr, topic, subExpression, consumerGroup, listner);
+    }
+
+    @Override
+    public void create() {
+        super.create();
+        consumer.setMessageModel(MessageModel.BROADCASTING);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalConsumer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalConsumer.java b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalConsumer.java
new file mode 100644
index 0000000..3f185d3
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalConsumer.java
@@ -0,0 +1,90 @@
+/*
+ * 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.rocketmq.test.client.rmq;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.test.clientinterface.AbstractMQConsumer;
+import org.apache.rocketmq.test.listener.AbstractListener;
+import org.apache.rocketmq.test.util.RandomUtil;
+
+public class RMQNormalConsumer extends AbstractMQConsumer {
+    private static Logger logger = Logger.getLogger(RMQNormalConsumer.class);
+    protected DefaultMQPushConsumer consumer = null;
+
+    public RMQNormalConsumer(String nsAddr, String topic, String subExpression,
+        String consumerGroup, AbstractListener listner) {
+        super(nsAddr, topic, subExpression, consumerGroup, listner);
+    }
+
+    public AbstractListener getListner() {
+        return listner;
+    }
+
+    public void setListner(AbstractListener listner) {
+        this.listner = listner;
+    }
+
+    public void create() {
+        consumer = new DefaultMQPushConsumer(consumerGroup);
+        consumer.setInstanceName(RandomUtil.getStringByUUID());
+        consumer.setNamesrvAddr(nsAddr);
+        try {
+            consumer.subscribe(topic, subExpression);
+        } catch (MQClientException e) {
+            logger.error("consumer subscribe failed!");
+            e.printStackTrace();
+        }
+        consumer.setMessageListener(listner);
+    }
+
+    public void start() {
+        try {
+            consumer.start();
+            logger.info(String.format("consumer[%s] started!", consumer.getConsumerGroup()));
+        } catch (MQClientException e) {
+            logger.error("consumer start failed!");
+            e.printStackTrace();
+        }
+    }
+
+    public void subscribe(String topic, String subExpression) {
+        try {
+            consumer.subscribe(topic, subExpression);
+        } catch (MQClientException e) {
+            logger.error("consumer subscribe failed!");
+            e.printStackTrace();
+        }
+    }
+
+    public void shutdown() {
+        consumer.shutdown();
+    }
+
+    @Override
+    public void clearMsg() {
+        this.listner.clearMsg();
+    }
+
+    public void restart() {
+        consumer.shutdown();
+        create();
+        start();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalProducer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalProducer.java b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalProducer.java
new file mode 100644
index 0000000..26b77fe
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQNormalProducer.java
@@ -0,0 +1,167 @@
+/*
+ * 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.rocketmq.test.client.rmq;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.clientinterface.AbstractMQProducer;
+import org.apache.rocketmq.test.sendresult.SendResult;
+
+public class RMQNormalProducer extends AbstractMQProducer {
+    private static Logger logger = Logger.getLogger(RMQNormalProducer.class);
+    private DefaultMQProducer producer = null;
+    private String nsAddr = null;
+
+    public RMQNormalProducer(String nsAddr, String topic) {
+        super(topic);
+        this.nsAddr = nsAddr;
+        create();
+        start();
+    }
+
+    public RMQNormalProducer(String nsAddr, String topic, String producerGroupName,
+        String producerInstanceName) {
+        super(topic);
+        this.producerGroupName = producerGroupName;
+        this.producerInstanceName = producerInstanceName;
+        this.nsAddr = nsAddr;
+
+        create();
+        start();
+    }
+
+    public DefaultMQProducer getProducer() {
+        return producer;
+    }
+
+    public void setProducer(DefaultMQProducer producer) {
+        this.producer = producer;
+    }
+
+    protected void create() {
+        producer = new DefaultMQProducer();
+        producer.setProducerGroup(getProducerGroupName());
+        producer.setInstanceName(getProducerInstanceName());
+
+        if (nsAddr != null) {
+            producer.setNamesrvAddr(nsAddr);
+        }
+
+    }
+
+    public void start() {
+        try {
+            producer.start();
+            super.setStartSuccess(true);
+        } catch (MQClientException e) {
+            super.setStartSuccess(false);
+            logger.error("producer start failed!");
+            e.printStackTrace();
+        }
+    }
+
+    public SendResult send(Object msg, Object orderKey) {
+        org.apache.rocketmq.client.producer.SendResult metaqResult = null;
+        Message metaqMsg = (Message) msg;
+        try {
+            long start = System.currentTimeMillis();
+            metaqResult = producer.send(metaqMsg);
+            this.msgRTs.addData(System.currentTimeMillis() - start);
+            if (isDebug) {
+                logger.info(metaqResult);
+            }
+            sendResult.setMsgId(metaqResult.getMsgId());
+            sendResult.setSendResult(metaqResult.getSendStatus().equals(SendStatus.SEND_OK));
+            sendResult.setBrokerIp(metaqResult.getMessageQueue().getBrokerName());
+            msgBodys.addData(new String(metaqMsg.getBody()));
+            originMsgs.addData(msg);
+            originMsgIndex.put(new String(metaqMsg.getBody()), metaqResult);
+        } catch (Exception e) {
+            if (isDebug) {
+                e.printStackTrace();
+            }
+
+            sendResult.setSendResult(false);
+            sendResult.setSendException(e);
+            errorMsgs.addData(msg);
+        }
+
+        return sendResult;
+    }
+
+    public void send(Map<MessageQueue, List<Object>> msgs) {
+        for (MessageQueue mq : msgs.keySet()) {
+            send(msgs.get(mq), mq);
+        }
+    }
+
+    public void send(List<Object> msgs, MessageQueue mq) {
+        for (Object msg : msgs) {
+            sendMQ((Message) msg, mq);
+        }
+    }
+
+    public SendResult sendMQ(Message msg, MessageQueue mq) {
+        org.apache.rocketmq.client.producer.SendResult metaqResult = null;
+        try {
+            long start = System.currentTimeMillis();
+            metaqResult = producer.send(msg, mq);
+            this.msgRTs.addData(System.currentTimeMillis() - start);
+            if (isDebug) {
+                logger.info(metaqResult);
+            }
+            sendResult.setMsgId(metaqResult.getMsgId());
+            sendResult.setSendResult(metaqResult.getSendStatus().equals(SendStatus.SEND_OK));
+            sendResult.setBrokerIp(metaqResult.getMessageQueue().getBrokerName());
+            msgBodys.addData(new String(msg.getBody()));
+            originMsgs.addData(msg);
+            originMsgIndex.put(new String(msg.getBody()), metaqResult);
+        } catch (Exception e) {
+            if (isDebug) {
+                e.printStackTrace();
+            }
+
+            sendResult.setSendResult(false);
+            sendResult.setSendException(e);
+            errorMsgs.addData(msg);
+        }
+
+        return sendResult;
+    }
+
+    public void shutdown() {
+        producer.shutdown();
+    }
+
+    @Override
+    public List<MessageQueue> getMessageQueue() {
+        List<MessageQueue> mqs = null;
+        try {
+            mqs = producer.fetchPublishMessageQueues(topic);
+        } catch (MQClientException e) {
+            e.printStackTrace();
+        }
+        return mqs;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQConsumer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQConsumer.java b/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQConsumer.java
new file mode 100644
index 0000000..a077129
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQConsumer.java
@@ -0,0 +1,112 @@
+/*
+ * 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.rocketmq.test.clientinterface;
+
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+public abstract class AbstractMQConsumer implements MQConsumer {
+    protected AbstractListener listner = null;
+    protected String nsAddr = null;
+    protected String topic = null;
+    protected String subExpression = null;
+    protected String consumerGroup = null;
+    protected boolean isDebug = false;
+
+    public AbstractMQConsumer() {
+    }
+
+    public AbstractMQConsumer(String nsAddr, String topic, String subExpression,
+        String consumerGroup, AbstractListener listner) {
+        this.topic = topic;
+        this.subExpression = subExpression;
+        this.consumerGroup = consumerGroup;
+        this.listner = listner;
+        this.nsAddr = nsAddr;
+    }
+
+    public AbstractMQConsumer(String topic, String subExpression) {
+        this.topic = topic;
+        this.subExpression = subExpression;
+    }
+
+    public void setDebug() {
+        if (listner != null) {
+            listner.setDebug(true);
+        }
+
+        isDebug = true;
+    }
+
+    public void setDebug(boolean isDebug) {
+        if (listner != null) {
+            listner.setDebug(isDebug);
+        }
+
+        this.isDebug = isDebug;
+    }
+
+    public void setSubscription(String topic, String subExpression) {
+        this.topic = topic;
+        this.subExpression = subExpression;
+    }
+
+    public AbstractListener getListner() {
+        return listner;
+    }
+
+    public void setListner(AbstractListener listner) {
+        this.listner = listner;
+    }
+
+    public String getNsAddr() {
+        return nsAddr;
+    }
+
+    public void setNsAddr(String nsAddr) {
+        this.nsAddr = nsAddr;
+    }
+
+    public String getTopic() {
+        return topic;
+    }
+
+    public void setTopic(String topic) {
+        this.topic = topic;
+    }
+
+    public String getSubExpression() {
+        return subExpression;
+    }
+
+    public void setSubExpression(String subExpression) {
+        this.subExpression = subExpression;
+    }
+
+    public String getConsumerGroup() {
+        return consumerGroup;
+    }
+
+    public void setConsumerGroup(String consumerGroup) {
+        this.consumerGroup = consumerGroup;
+    }
+
+    public void clearMsg() {
+        listner.clearMsg();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQProducer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQProducer.java b/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQProducer.java
new file mode 100644
index 0000000..8201e63
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/clientinterface/AbstractMQProducer.java
@@ -0,0 +1,151 @@
+/*
+ * 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.rocketmq.test.clientinterface;
+
+import java.util.Date;
+import java.util.List;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.sendresult.SendResult;
+import org.apache.rocketmq.test.util.RandomUtil;
+import org.apache.rocketmq.test.util.TestUtil;
+
+public abstract class AbstractMQProducer extends MQCollector implements MQProducer {
+    protected String topic = null;
+
+    protected SendResult sendResult = new SendResult();
+    protected boolean startSuccess = false;
+    protected String producerGroupName = null;
+    protected String producerInstanceName = null;
+    protected boolean isDebug = false;
+
+    public AbstractMQProducer(String topic) {
+        super();
+        producerGroupName = RandomUtil.getStringByUUID();
+        producerInstanceName = RandomUtil.getStringByUUID();
+        this.topic = topic;
+
+    }
+
+    public AbstractMQProducer(String topic, String originMsgCollector, String msgBodyCollector) {
+        super(originMsgCollector, msgBodyCollector);
+        producerGroupName = RandomUtil.getStringByUUID();
+        producerInstanceName = RandomUtil.getStringByUUID();
+        this.topic = topic;
+    }
+
+    public boolean isStartSuccess() {
+        return startSuccess;
+    }
+
+    public void setStartSuccess(boolean startSuccess) {
+        this.startSuccess = startSuccess;
+    }
+
+    public String getProducerInstanceName() {
+        return producerInstanceName;
+    }
+
+    public void setProducerInstanceName(String producerInstanceName) {
+        this.producerInstanceName = producerInstanceName;
+    }
+
+    public String getProducerGroupName() {
+        return producerGroupName;
+    }
+
+    public void setProducerGroupName(String producerGroupName) {
+        this.producerGroupName = producerGroupName;
+    }
+
+    public void setDebug() {
+        isDebug = true;
+    }
+
+    public void setDebug(boolean isDebug) {
+        this.isDebug = isDebug;
+    }
+
+    public void setRun() {
+        isDebug = false;
+    }
+
+    public List<MessageQueue> getMessageQueue() {
+        return null;
+    }
+
+    private Object getMessage() {
+        return this.getMessageByTag(null);
+    }
+
+    public Object getMessageByTag(String tag) {
+        Object objMsg = null;
+        if (this instanceof RMQNormalProducer) {
+            org.apache.rocketmq.common.message.Message msg = new org.apache.rocketmq.common.message.Message(
+                topic, (RandomUtil.getStringByUUID() + "." + new Date()).getBytes());
+            objMsg = msg;
+            if (tag != null) {
+                msg.setTags(tag);
+            }
+        }
+        return objMsg;
+    }
+
+    public void send() {
+        Object msg = getMessage();
+        send(msg, null);
+    }
+
+    public void send(Object msg) {
+        send(msg, null);
+    }
+
+    public void send(long msgNum) {
+        for (int i = 0; i < msgNum; i++) {
+            this.send();
+        }
+    }
+
+    public void send(long msgNum, int intervalMills) {
+        for (int i = 0; i < msgNum; i++) {
+            this.send();
+            TestUtil.waitForMonment(intervalMills);
+        }
+    }
+
+    public void send(String tag, int msgSize) {
+        for (int i = 0; i < msgSize; i++) {
+            Object msg = getMessageByTag(tag);
+            send(msg, null);
+        }
+    }
+
+    public void send(String tag, int msgSize, int intervalMills) {
+        for (int i = 0; i < msgSize; i++) {
+            Object msg = getMessageByTag(tag);
+            send(msg, null);
+            TestUtil.waitForMonment(intervalMills);
+        }
+    }
+
+    public void send(List<Object> msgs) {
+        for (Object msg : msgs) {
+            this.send(msg, null);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java
new file mode 100644
index 0000000..42d4b62
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java
@@ -0,0 +1,108 @@
+/*
+ * 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.rocketmq.test.clientinterface;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.rocketmq.test.util.RandomUtil;
+import org.apache.rocketmq.test.util.data.collect.DataCollector;
+import org.apache.rocketmq.test.util.data.collect.DataCollectorManager;
+
+public abstract class MQCollector {
+    protected DataCollector msgBodys = null;
+    protected DataCollector originMsgs = null;
+    protected DataCollector errorMsgs = null;
+    protected Map<Object, Object> originMsgIndex = null;
+    protected Collection<Object> msgBodysCopy = null;
+
+    protected DataCollector msgRTs = null;
+
+    public MQCollector() {
+        msgBodys = DataCollectorManager.getInstance()
+            .fetchListDataCollector(RandomUtil.getStringByUUID());
+        originMsgs = DataCollectorManager.getInstance()
+            .fetchListDataCollector(RandomUtil.getStringByUUID());
+        errorMsgs = DataCollectorManager.getInstance()
+            .fetchListDataCollector(RandomUtil.getStringByUUID());
+        originMsgIndex = new ConcurrentHashMap<Object, Object>();
+        msgRTs = DataCollectorManager.getInstance()
+            .fetchListDataCollector(RandomUtil.getStringByUUID());
+    }
+
+    public MQCollector(String originMsgCollector, String msgBodyCollector) {
+        originMsgs = DataCollectorManager.getInstance().fetchDataCollector(originMsgCollector);
+        msgBodys = DataCollectorManager.getInstance().fetchDataCollector(msgBodyCollector);
+    }
+
+    public Collection<Object> getAllMsgBody() {
+        return msgBodys.getAllData();
+    }
+
+    public Collection<Object> getAllOriginMsg() {
+        return originMsgs.getAllData();
+    }
+
+    public Object getFirstMsg() {
+        return ((List<Object>) originMsgs.getAllData()).get(0);
+    }
+
+    public Collection<Object> getAllUndupMsgBody() {
+        return msgBodys.getAllDataWithoutDuplicate();
+    }
+
+    public Collection<Object> getAllUndupOriginMsg() {
+        return originMsgs.getAllData();
+    }
+
+    public Collection<Object> getSendErrorMsg() {
+        return errorMsgs.getAllData();
+    }
+
+    public Collection<Object> getMsgRTs() {
+        return msgRTs.getAllData();
+    }
+
+    public Map<Object, Object> getOriginMsgIndex() {
+        return originMsgIndex;
+    }
+
+    public Collection<Object> getMsgBodysCopy() {
+        msgBodysCopy = new ArrayList<Object>();
+        msgBodysCopy.addAll(msgBodys.getAllData());
+        return msgBodysCopy;
+    }
+
+    public void clearMsg() {
+        msgBodys.resetData();
+        originMsgs.resetData();
+        errorMsgs.resetData();
+        originMsgIndex.clear();
+        msgRTs.resetData();
+    }
+
+    public void lockCollectors() {
+        msgBodys.lockIncrement();
+        originMsgs.lockIncrement();
+        errorMsgs.lockIncrement();
+        msgRTs.lockIncrement();
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQConsumer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQConsumer.java b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQConsumer.java
new file mode 100644
index 0000000..aaa4b27
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQConsumer.java
@@ -0,0 +1,26 @@
+/*
+ * 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.rocketmq.test.clientinterface;
+
+public interface MQConsumer {
+    void create();
+
+    void start();
+
+    void shutdown();
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQProducer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQProducer.java b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQProducer.java
new file mode 100644
index 0000000..795457d
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQProducer.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rocketmq.test.clientinterface;
+
+import org.apache.rocketmq.test.sendresult.SendResult;
+
+public interface MQProducer {
+    SendResult send(Object msg, Object arg);
+
+    void setDebug();
+
+    void setRun();
+
+    void shutdown();
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java b/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java
new file mode 100644
index 0000000..b5b3fdd
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java
@@ -0,0 +1,45 @@
+/*
+ * 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.rocketmq.test.factory;
+
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+public class ConsumerFactory {
+
+    public static RMQNormalConsumer getRMQNormalConsumer(String nsAddr, String consumerGroup,
+        String topic, String subExpression,
+        AbstractListener listner) {
+        RMQNormalConsumer consumer = new RMQNormalConsumer(nsAddr, topic, subExpression,
+            consumerGroup, listner);
+        consumer.create();
+        consumer.start();
+        return consumer;
+    }
+
+    public static RMQBroadCastConsumer getRMQBroadCastConsumer(String nsAddr, String consumerGroup,
+        String topic, String subExpression,
+        AbstractListener listner) {
+        RMQBroadCastConsumer consumer = new RMQBroadCastConsumer(nsAddr, topic, subExpression,
+            consumerGroup, listner);
+        consumer.create();
+        consumer.start();
+        return consumer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/factory/MQMessageFactory.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/factory/MQMessageFactory.java b/test/src/main/java/org/apache/rocketmq/test/factory/MQMessageFactory.java
new file mode 100644
index 0000000..f998fcb
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/factory/MQMessageFactory.java
@@ -0,0 +1,128 @@
+/*
+ * 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.rocketmq.test.factory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.util.RandomUtil;
+
+public class MQMessageFactory {
+    private static Integer index = 0;
+
+    public static List<Object> getRMQMessage(String tag, String topic, int msgSize) {
+        List<Object> msgs = new ArrayList<Object>();
+        for (int i = 0; i < msgSize; i++) {
+            msgs.add(new Message(topic, tag, RandomUtil.getStringByUUID().getBytes()));
+        }
+
+        return msgs;
+    }
+
+    public static List<Object> getRMQMessage(List<String> tags, String topic, int msgSize) {
+        List<Object> msgs = new ArrayList<Object>();
+        for (int i = 0; i < msgSize; i++) {
+            for (String tag : tags) {
+                msgs.add(new Message(topic, tag, RandomUtil.getStringByUUID().getBytes()));
+            }
+        }
+        return msgs;
+    }
+
+    public static List<Object> getMessageBody(List<Object> msgs) {
+        List<Object> msgBodys = new ArrayList<Object>();
+        for (Object msg : msgs) {
+            msgBodys.add(new String(((Message) msg).getBody()));
+        }
+
+        return msgBodys;
+    }
+
+    public static Collection<Object> getMessage(Collection<Object>... msgs) {
+        Collection<Object> allMsgs = new ArrayList<Object>();
+        for (Collection<Object> msg : msgs) {
+            allMsgs.addAll(msg);
+        }
+        return allMsgs;
+    }
+
+    public static List<Object> getDelayMsg(String topic, int delayLevel, int msgSize) {
+        List<Object> msgs = new ArrayList<Object>();
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, RandomUtil.getStringByUUID().getBytes());
+            msg.setDelayTimeLevel(delayLevel);
+            msgs.add(msg);
+        }
+        return msgs;
+    }
+
+    public static List<Object> getKeyMsg(String topic, String key, int msgSize) {
+        List<Object> msgs = new ArrayList<Object>();
+        for (int i = 0; i < msgSize; i++) {
+            Message msg = new Message(topic, null, key, RandomUtil.getStringByUUID().getBytes());
+            msgs.add(msg);
+        }
+        return msgs;
+    }
+
+    public static Map<MessageQueue, List<Object>> getMsgByMQ(MessageQueue mq, int msgSize) {
+        List<MessageQueue> mqs = new ArrayList<MessageQueue>();
+        mqs.add(mq);
+        return getMsgByMQ(mqs, msgSize);
+    }
+
+    public static Map<MessageQueue, List<Object>> getMsgByMQ(List<MessageQueue> mqs, int msgSize) {
+        return getMsgByMQ(mqs, msgSize, null);
+    }
+
+    public static Map<MessageQueue, List<Object>> getMsgByMQ(List<MessageQueue> mqs, int msgSize,
+        String tag) {
+        Map<MessageQueue, List<Object>> msgs = new HashMap<MessageQueue, List<Object>>();
+        for (MessageQueue mq : mqs) {
+            msgs.put(mq, getMsg(mq.getTopic(), msgSize, tag));
+        }
+        return msgs;
+    }
+
+    public static List<Object> getMsg(String topic, int msgSize) {
+        return getMsg(topic, msgSize, null);
+    }
+
+    public static List<Object> getMsg(String topic, int msgSize, String tag) {
+        List<Object> msgs = new ArrayList<Object>();
+        while (msgSize > 0) {
+            Message msg = new Message(topic, (index++).toString().getBytes());
+            if (tag != null) {
+                msg.setTags(tag);
+            }
+            msgs.add(msg);
+            msgSize--;
+        }
+
+        return msgs;
+    }
+
+    public static List<MessageQueue> getMessageQueues(MessageQueue... mq) {
+        return Arrays.asList(mq);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/factory/MessageFactory.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/factory/MessageFactory.java b/test/src/main/java/org/apache/rocketmq/test/factory/MessageFactory.java
new file mode 100644
index 0000000..8f71700
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/factory/MessageFactory.java
@@ -0,0 +1,62 @@
+/*
+ * 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.rocketmq.test.factory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.test.util.RandomUtils;
+
+public class MessageFactory {
+
+    public static Message getRandomMessage(String topic) {
+        return getStringMessage(topic, RandomUtils.getStringByUUID());
+    }
+
+    public static Message getStringMessage(String topic, String body) {
+        Message msg = new Message(topic, body.getBytes());
+        return msg;
+    }
+
+    public static Message getStringMessageByTag(String topic, String tags, String body) {
+        Message msg = new Message(topic, tags, body.getBytes());
+        return msg;
+    }
+
+    public static Message getRandomMessageByTag(String topic, String tags) {
+        return getStringMessageByTag(topic, tags, RandomUtils.getStringByUUID());
+    }
+
+    public static Collection<Message> getRandomMessageList(String topic, int size) {
+        List<Message> msgList = new ArrayList<Message>();
+        for (int i = 0; i < size; i++) {
+            msgList.add(getRandomMessage(topic));
+        }
+        return msgList;
+    }
+
+    public static Collection<Message> getRandomMessageListByTag(String topic, String tags, int size) {
+        List<Message> msgList = new ArrayList<Message>();
+        for (int i = 0; i < size; i++) {
+            msgList.add(getRandomMessageByTag(topic, tags));
+        }
+        return msgList;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/factory/ProducerFactory.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/factory/ProducerFactory.java b/test/src/main/java/org/apache/rocketmq/test/factory/ProducerFactory.java
new file mode 100644
index 0000000..66767cc
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/factory/ProducerFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.rocketmq.test.factory;
+
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.test.util.RandomUtil;
+
+public class ProducerFactory {
+
+    public static DefaultMQProducer getRMQProducer(String ns) {
+        DefaultMQProducer producer = new DefaultMQProducer(RandomUtil.getStringByUUID());
+        producer.setNamesrvAddr(ns);
+        try {
+            producer.start();
+        } catch (MQClientException e) {
+            e.printStackTrace();
+        }
+
+        return producer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/factory/SendCallBackFactory.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/factory/SendCallBackFactory.java b/test/src/main/java/org/apache/rocketmq/test/factory/SendCallBackFactory.java
new file mode 100644
index 0000000..64764c6
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/factory/SendCallBackFactory.java
@@ -0,0 +1,35 @@
+/*
+ * 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.rocketmq.test.factory;
+
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendResult;
+
+public class SendCallBackFactory {
+    public static SendCallback getSendCallBack() {
+        return new SendCallback() {
+            @Override
+            public void onSuccess(SendResult sendResult) {
+            }
+
+            @Override
+            public void onException(Throwable throwable) {
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/factory/TagMessage.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/factory/TagMessage.java b/test/src/main/java/org/apache/rocketmq/test/factory/TagMessage.java
new file mode 100644
index 0000000..b7eb6a6
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/factory/TagMessage.java
@@ -0,0 +1,108 @@
+/*
+ * 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.rocketmq.test.factory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TagMessage {
+    private List<String> tags = null;
+    private String topic = null;
+    private int msgSize = 0;
+    private Map<String, List<Object>> rmqMsgs = new HashMap<String, List<Object>>();
+
+    public TagMessage(String tag, String topic, int msgSize) {
+        String[] tags = {tag};
+        this.tags = Arrays.asList(tags);
+        this.topic = topic;
+        this.msgSize = msgSize;
+
+        init();
+    }
+
+    public TagMessage(String[] tags, String topic, int msgSize) {
+        this(Arrays.asList(tags), topic, msgSize);
+    }
+
+    public TagMessage(List<String> tags, String topic, int msgSize) {
+        this.tags = tags;
+        this.topic = topic;
+        this.msgSize = msgSize;
+
+        init();
+    }
+
+    private void init() {
+        for (String tag : tags) {
+            List<Object> tagMsgs = MQMessageFactory.getRMQMessage(tag, topic, msgSize);
+            rmqMsgs.put(tag, tagMsgs);
+        }
+    }
+
+    public List<Object> getMessageByTag(String tag) {
+        if (tags.contains(tag)) {
+            return rmqMsgs.get(tag);
+        } else {
+            return new ArrayList<Object>();
+        }
+    }
+
+    public List<Object> getMixedTagMessages() {
+        List<Object> mixedMsgs = new ArrayList<Object>();
+        for (int i = 0; i < msgSize; i++) {
+            for (String tag : tags) {
+                mixedMsgs.add(rmqMsgs.get(tag).get(i));
+            }
+        }
+
+        return mixedMsgs;
+    }
+
+    public List<Object> getMessageBodyByTag(String tag) {
+        if (tags.contains(tag)) {
+            return MQMessageFactory.getMessageBody(rmqMsgs.get(tag));
+        } else {
+            return new ArrayList<Object>();
+        }
+    }
+
+    public List<Object> getMessageBodyByTag(String... tag) {
+        return this.getMessageBodyByTag(Arrays.asList(tag));
+    }
+
+    public List<Object> getMessageBodyByTag(List<String> tags) {
+        List<Object> msgBodys = new ArrayList<Object>();
+        for (String tag : tags) {
+            msgBodys.addAll(MQMessageFactory.getMessageBody(rmqMsgs.get(tag)));
+        }
+        return msgBodys;
+    }
+
+    public List<Object> getAllTagMessageBody() {
+        List<Object> msgs = new ArrayList<Object>();
+        for (String tag : tags) {
+            msgs.addAll(MQMessageFactory.getMessageBody(rmqMsgs.get(tag)));
+        }
+
+        return msgs;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java b/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java
new file mode 100644
index 0000000..974434a
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java
@@ -0,0 +1,104 @@
+/*
+ * 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.rocketmq.test.listener;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.consumer.listener.MessageListener;
+import org.apache.rocketmq.test.clientinterface.MQCollector;
+import org.apache.rocketmq.test.util.TestUtil;
+
+public class AbstractListener extends MQCollector implements MessageListener {
+    public static Logger logger = Logger.getLogger(AbstractListener.class);
+    protected boolean isDebug = false;
+    protected String listnerName = null;
+    protected Collection<Object> allSendMsgs = null;
+
+    public AbstractListener() {
+        super();
+    }
+
+    public AbstractListener(String listnerName) {
+        super();
+        this.listnerName = listnerName;
+    }
+
+    public AbstractListener(String originMsgCollector, String msgBodyCollector) {
+        super(originMsgCollector, msgBodyCollector);
+    }
+
+    public boolean isDebug() {
+        return isDebug;
+    }
+
+    public void setDebug(boolean debug) {
+        isDebug = debug;
+    }
+
+    public void waitForMessageConsume(int timeoutMills) {
+        TestUtil.waitForMonment(timeoutMills);
+    }
+
+    public void stopRecv() {
+        super.lockCollectors();
+    }
+
+    public Collection<Object> waitForMessageConsume(Collection<Object> allSendMsgs,
+        int timeoutMills) {
+        this.allSendMsgs = allSendMsgs;
+        List<Object> sendMsgs = new ArrayList<Object>();
+        sendMsgs.addAll(allSendMsgs);
+
+        long curTime = System.currentTimeMillis();
+        while (!sendMsgs.isEmpty()) {
+            Iterator<Object> iter = sendMsgs.iterator();
+            while (iter.hasNext()) {
+                Object msg = iter.next();
+                if (msgBodys.getAllData().contains(msg)) {
+                    iter.remove();
+                }
+            }
+            if (sendMsgs.isEmpty()) {
+                break;
+            } else {
+                if (System.currentTimeMillis() - curTime >= timeoutMills) {
+                    logger.error(String.format("timeout but  [%s]  not recv all send messages!",
+                        listnerName));
+                    break;
+                } else {
+                    logger.info(String.format("[%s] still [%s] msg not recv!", listnerName,
+                        sendMsgs.size()));
+                    TestUtil.waitForMonment(500);
+                }
+            }
+        }
+
+        return sendMsgs;
+    }
+
+    public void waitForMessageConsume(Map<Object, Object> sendMsgIndex, int timeoutMills) {
+        Collection<Object> notRecvMsgs = waitForMessageConsume(sendMsgIndex.keySet(), timeoutMills);
+        for (Object object : notRecvMsgs) {
+            logger.info(sendMsgIndex.get(object));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQDelayListner.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQDelayListner.java b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQDelayListner.java
new file mode 100644
index 0000000..b4a0870
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQDelayListner.java
@@ -0,0 +1,61 @@
+/*
+ * 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.rocketmq.test.listener.rmq.concurrent;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.test.listener.AbstractListener;
+import org.apache.rocketmq.test.util.RandomUtil;
+import org.apache.rocketmq.test.util.data.collect.DataCollector;
+import org.apache.rocketmq.test.util.data.collect.DataCollectorManager;
+
+public class RMQDelayListner extends AbstractListener implements MessageListenerConcurrently {
+    private DataCollector msgDelayTimes = null;
+
+    public RMQDelayListner() {
+        msgDelayTimes = DataCollectorManager.getInstance()
+            .fetchDataCollector(RandomUtil.getStringByUUID());
+    }
+
+    public Collection<Object> getMsgDelayTimes() {
+        return msgDelayTimes.getAllData();
+    }
+
+    public void resetMsgDelayTimes() {
+        msgDelayTimes.resetData();
+    }
+
+    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
+        ConsumeConcurrentlyContext consumeConcurrentlyContext) {
+        long recvTime = System.currentTimeMillis();
+        for (MessageExt msg : msgs) {
+            if (isDebug) {
+                logger.info(listnerName + ":" + msg);
+            }
+
+            msgBodys.addData(new String(msg.getBody()));
+            originMsgs.addData(msg);
+            msgDelayTimes.addData(Math.abs(recvTime - msg.getBornTimestamp()));
+        }
+        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java
new file mode 100644
index 0000000..0d40881
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java
@@ -0,0 +1,70 @@
+/*
+ * 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.rocketmq.test.listener.rmq.concurrent;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+public class RMQNormalListner extends AbstractListener implements MessageListenerConcurrently {
+    private ConsumeConcurrentlyStatus consumeStatus = ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+    private AtomicInteger msgIndex = new AtomicInteger(0);
+
+    public RMQNormalListner() {
+        super();
+    }
+
+    public RMQNormalListner(String listnerName) {
+        super(listnerName);
+    }
+
+    public RMQNormalListner(ConsumeConcurrentlyStatus consumeStatus) {
+        super();
+        this.consumeStatus = consumeStatus;
+    }
+
+    public RMQNormalListner(String originMsgCollector, String msgBodyCollector) {
+        super(originMsgCollector, msgBodyCollector);
+    }
+
+    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
+        ConsumeConcurrentlyContext consumeConcurrentlyContext) {
+        for (MessageExt msg : msgs) {
+            msgIndex.getAndIncrement();
+            if (isDebug) {
+                if (listnerName != null && listnerName != "") {
+                    logger.info(listnerName + ":" + msgIndex.get() + ":"
+                        + String.format("msgid:%s broker:%s queueId:%s offset:%s",
+                        msg.getMsgId(), msg.getStoreHost(), msg.getQueueId(),
+                        msg.getQueueOffset()));
+                } else {
+                    logger.info(msg);
+                }
+            }
+
+            msgBodys.addData(new String(msg.getBody()));
+            originMsgs.addData(msg);
+            originMsgIndex.put(new String(msg.getBody()), msg);
+        }
+        return consumeStatus;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/listener/rmq/order/RMQOrderListener.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/listener/rmq/order/RMQOrderListener.java b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/order/RMQOrderListener.java
new file mode 100644
index 0000000..91883d8
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/order/RMQOrderListener.java
@@ -0,0 +1,85 @@
+/*
+ * 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.rocketmq.test.listener.rmq.order;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+public class RMQOrderListener extends AbstractListener implements MessageListenerOrderly {
+    private Map<String/* brokerId_brokerIp */, Collection<Object>> msgs = new ConcurrentHashMap<String, Collection<Object>>();
+
+    public RMQOrderListener() {
+        super();
+    }
+
+    public RMQOrderListener(String listnerName) {
+        super(listnerName);
+    }
+
+    public RMQOrderListener(String originMsgCollector, String msgBodyCollector) {
+        super(originMsgCollector, msgBodyCollector);
+    }
+
+    public Collection<Collection<Object>> getMsgs() {
+        return msgs.values();
+    }
+
+    private void putMsg(MessageExt msg) {
+        Collection<Object> msgQueue = null;
+        String key = getKey(msg.getQueueId(), msg.getStoreHost().toString());
+        if (!msgs.containsKey(key)) {
+            msgQueue = new ArrayList<Object>();
+        } else {
+            msgQueue = msgs.get(key);
+        }
+
+        msgQueue.add(new String(msg.getBody()));
+        msgs.put(key, msgQueue);
+    }
+
+    private String getKey(int queueId, String brokerIp) {
+        return String.format("%s_%s", queueId, brokerIp);
+    }
+
+    public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs,
+        ConsumeOrderlyContext context) {
+        for (MessageExt msg : msgs) {
+            if (isDebug) {
+                if (listnerName != null && listnerName != "") {
+                    logger.info(listnerName + ": " + msg);
+                } else {
+                    logger.info(msg);
+                }
+            }
+
+            putMsg(msg);
+            msgBodys.addData(new String(msg.getBody()));
+            originMsgs.addData(msg);
+        }
+
+        return ConsumeOrderlyStatus.SUCCESS;
+    }
+}



[08/13] incubator-rocketmq git commit: [RocketMQ-58] Add integration test for RocketMQ, also thanks @fenglianghfl for this commit, closes apache/incubator-rocketmq#46

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/message/MessageQueueMsg.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/message/MessageQueueMsg.java b/test/src/main/java/org/apache/rocketmq/test/message/MessageQueueMsg.java
new file mode 100644
index 0000000..38c2b6b
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/message/MessageQueueMsg.java
@@ -0,0 +1,62 @@
+/*
+ * 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.rocketmq.test.message;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+
+public class MessageQueueMsg {
+    private Map<MessageQueue, List<Object>> msgsWithMQ = null;
+    private Map<Integer, List<Object>> msgsWithMQId = null;
+    private Collection<Object> msgBodys = null;
+
+    public MessageQueueMsg(List<MessageQueue> mqs, int msgSize) {
+        this(mqs, msgSize, null);
+    }
+
+    public MessageQueueMsg(List<MessageQueue> mqs, int msgSize, String tag) {
+        msgsWithMQ = MQMessageFactory.getMsgByMQ(mqs, msgSize, tag);
+        msgsWithMQId = new HashMap<Integer, List<Object>>();
+        msgBodys = new ArrayList<Object>();
+        init();
+    }
+
+    public Map<MessageQueue, List<Object>> getMsgsWithMQ() {
+        return msgsWithMQ;
+    }
+
+    public Map<Integer, List<Object>> getMsgWithMQId() {
+        return msgsWithMQId;
+    }
+
+    public Collection<Object> getMsgBodys() {
+        return msgBodys;
+    }
+
+    private void init() {
+        for (MessageQueue mq : msgsWithMQ.keySet()) {
+            msgsWithMQId.put(mq.getQueueId(), msgsWithMQ.get(mq));
+            msgBodys.addAll(MQMessageFactory.getMessageBody(msgsWithMQ.get(mq)));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/sendresult/SendResult.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/sendresult/SendResult.java b/test/src/main/java/org/apache/rocketmq/test/sendresult/SendResult.java
new file mode 100644
index 0000000..d53ee7d
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/sendresult/SendResult.java
@@ -0,0 +1,62 @@
+/*
+ * 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.rocketmq.test.sendresult;
+
+public class SendResult {
+    private boolean sendResult = false;
+    private String msgId = null;
+    private Exception sendException = null;
+    private String brokerIp = null;
+
+    public String getBrokerIp() {
+        return brokerIp;
+    }
+
+    public void setBrokerIp(String brokerIp) {
+        this.brokerIp = brokerIp;
+    }
+
+    public boolean isSendResult() {
+        return sendResult;
+    }
+
+    public void setSendResult(boolean sendResult) {
+        this.sendResult = sendResult;
+    }
+
+    public String getMsgId() {
+        return msgId;
+    }
+
+    public void setMsgId(String msgId) {
+        this.msgId = msgId;
+    }
+
+    public Exception getSendException() {
+        return sendException;
+    }
+
+    public void setSendException(Exception sendException) {
+        this.sendException = sendException;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("sendstatus:%s msgId:%s", sendResult, msgId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/Condition.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/Condition.java b/test/src/main/java/org/apache/rocketmq/test/util/Condition.java
new file mode 100644
index 0000000..3c5f403
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/Condition.java
@@ -0,0 +1,23 @@
+/*
+ * 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.rocketmq.test.util;
+
+public interface Condition {
+    boolean meetCondition();
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/DuplicateMessageInfo.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/DuplicateMessageInfo.java b/test/src/main/java/org/apache/rocketmq/test/util/DuplicateMessageInfo.java
new file mode 100644
index 0000000..8bd93b6
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/DuplicateMessageInfo.java
@@ -0,0 +1,137 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class DuplicateMessageInfo<T> {
+
+    public void checkDuplicatedMessageInfo(boolean bPrintLog,
+        List<List<T>> lQueueList) throws IOException {
+        int msgListSize = lQueueList.size();
+        int maxmsgList = 0;
+        Map<T, Integer> msgIdMap = new HashMap<T, Integer>();
+        Map<Integer, Integer> dupMsgMap = new HashMap<Integer, Integer>();
+
+        for (int i = 0; i < msgListSize; i++) {
+            if (maxmsgList < lQueueList.get(i).size())
+                maxmsgList = lQueueList.get(i).size();
+        }
+
+        List<StringBuilder> strBQueue = new LinkedList<StringBuilder>();
+        for (int i = 0; i < msgListSize; i++)
+            strBQueue.add(new StringBuilder());
+
+        for (int msgListIndex = 0; msgListIndex < maxmsgList; msgListIndex++) {
+            for (int msgQueueListIndex = 0; msgQueueListIndex < msgListSize; msgQueueListIndex++) {
+                if (msgListIndex < lQueueList.get(msgQueueListIndex).size()) {
+                    if (msgIdMap.containsKey(lQueueList.get(msgQueueListIndex).get(msgListIndex))) {
+                        if (dupMsgMap.containsKey(msgQueueListIndex)) {
+                            int dupMsgCount = dupMsgMap.get(msgQueueListIndex);
+                            dupMsgCount++;
+                            dupMsgMap.remove(msgQueueListIndex);
+                            dupMsgMap.put(msgQueueListIndex, dupMsgCount);
+                        } else {
+                            dupMsgMap.put(msgQueueListIndex, 1);
+                        }
+
+                        strBQueue.get(msgQueueListIndex).append("" + msgQueueListIndex + "\t" +
+                            msgIdMap.get(lQueueList.get(msgQueueListIndex).get(msgListIndex)) + "\t"
+                            + lQueueList.get(msgQueueListIndex).get(msgListIndex) + "\r\n");
+                    } else {
+                        msgIdMap.put(lQueueList.get(msgQueueListIndex).get(msgListIndex), msgQueueListIndex);
+                    }
+                }
+            }
+        }
+
+        int msgTotalNum = getMsgTotalNumber(lQueueList);
+        int msgTotalDupNum = getDuplicateMsgNum(dupMsgMap);
+        int msgNoDupNum = msgTotalNum - msgTotalDupNum;
+        float msgDupRate = ((float) msgTotalDupNum / (float) msgTotalNum) * 100.0f;
+        StringBuilder strBuilder = new StringBuilder();
+
+        strBuilder.append("msgTotalNum:" + msgTotalNum + "\r\n");
+        strBuilder.append("msgTotalDupNum:" + msgTotalDupNum + "\r\n");
+        strBuilder.append("msgNoDupNum:" + msgNoDupNum + "\r\n");
+        strBuilder.append("msgDupRate" + getFloatNumString(msgDupRate) + "%\r\n");
+
+        strBuilder.append("queue\tmsg(dupNum/dupRate)\tdupRate\r\n");
+        for (int i = 0; i < dupMsgMap.size(); i++) {
+            int msgDupNum = dupMsgMap.get(i);
+            int msgNum = lQueueList.get(i).size();
+            float msgQueueDupRate = ((float) msgDupNum / (float) msgTotalDupNum) * 100.0f;
+            float msgQueueInnerDupRate = ((float) msgDupNum / (float) msgNum) * 100.0f;
+
+            strBuilder.append(i + "\t" + msgDupNum + "/" + getFloatNumString(msgQueueDupRate) + "%" + "\t\t" +
+                getFloatNumString(msgQueueInnerDupRate) + "%\r\n");
+        }
+
+        System.out.print(strBuilder.toString());
+        String titleString = "queue\tdupQueue\tdupMsg\r\n";
+        System.out.print(titleString);
+
+        for (int i = 0; i < msgListSize; i++)
+            System.out.print(strBQueue.get(i).toString());
+
+        if (bPrintLog) {
+            String logFileNameStr = "D:" + File.separator + "checkDuplicatedMessageInfo.txt";
+            File logFileNameFile = new File(logFileNameStr);
+            OutputStream out = new FileOutputStream(logFileNameFile, true);
+
+            String strToWrite;
+            byte[] byteToWrite;
+            strToWrite = strBuilder.toString() + titleString;
+            for (int i = 0; i < msgListSize; i++)
+                strToWrite += strBQueue.get(i).toString() + "\r\n";
+
+            byteToWrite = strToWrite.getBytes();
+            out.write(byteToWrite);
+            out.close();
+        }
+    }
+
+    private int getMsgTotalNumber(List<List<T>> lQueueList) {
+        int msgTotalNum = 0;
+        for (int i = 0; i < lQueueList.size(); i++) {
+            msgTotalNum += lQueueList.get(i).size();
+        }
+        return msgTotalNum;
+    }
+
+    private int getDuplicateMsgNum(Map<Integer, Integer> msgDupMap) {
+        int msgDupNum = 0;
+        for (int i = 0; i < msgDupMap.size(); i++) {
+            msgDupNum += msgDupMap.get(i);
+        }
+        return msgDupNum;
+    }
+
+    private String getFloatNumString(float fNum) {
+        DecimalFormat dcmFmt = new DecimalFormat("0.00");
+        return dcmFmt.format(fNum);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/FileUtil.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/FileUtil.java b/test/src/main/java/org/apache/rocketmq/test/util/FileUtil.java
new file mode 100644
index 0000000..44db782
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/FileUtil.java
@@ -0,0 +1,108 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Properties;
+
+public class FileUtil {
+    private static String lineSeperator = System.getProperty("line.separator");
+
+    private String filePath = "";
+    private String fileName = "";
+
+    public FileUtil(String filePath, String fileName) {
+        this.filePath = filePath;
+        this.fileName = fileName;
+    }
+
+    public static void main(String args[]) {
+        String filePath = FileUtil.class.getResource("/").getPath();
+        String fileName = "test.txt";
+        FileUtil fileUtil = new FileUtil(filePath, fileName);
+        Properties properties = new Properties();
+        properties.put("xx", "yy");
+        properties.put("yy", "xx");
+        fileUtil.writeProperties(properties);
+    }
+
+    public void deleteFile() {
+        File file = new File(filePath + File.separator + fileName);
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    public void appendFile(String content) {
+        File file = openFile();
+        String newContent = lineSeperator + content;
+        writeFile(file, newContent, true);
+    }
+
+    public void coverFile(String content) {
+        File file = openFile();
+        writeFile(file, content, false);
+    }
+
+    public void writeProperties(Properties properties) {
+        String content = getPropertiesAsString(properties);
+        this.coverFile(content);
+    }
+
+    private String getPropertiesAsString(Properties properties) {
+        StringBuilder sb = new StringBuilder();
+        for (Object key : properties.keySet()) {
+            sb.append(key).append("=").append(properties.getProperty((String) key))
+                .append(lineSeperator);
+        }
+        return sb.toString();
+    }
+
+    private void writeFile(File file, String content, boolean append) {
+        FileWriter writer = null;
+        try {
+            writer = new FileWriter(file.getAbsoluteFile(), append);
+            writer.write(content);
+            writer.flush();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private File openFile() {
+        File file = new File(filePath + File.separator + fileName);
+        if (!file.exists()) {
+            try {
+                file.createNewFile();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return file;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java b/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java
new file mode 100644
index 0000000..c3e0572
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java
@@ -0,0 +1,164 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.util.HashMap;
+import java.util.Set;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.admin.TopicStatsTable;
+import org.apache.rocketmq.common.protocol.body.ClusterInfo;
+import org.apache.rocketmq.common.protocol.route.BrokerData;
+import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
+import org.apache.rocketmq.tools.command.CommandUtil;
+
+public class MQAdmin {
+    private static Logger log = Logger.getLogger(MQAdmin.class);
+
+    public static boolean createTopic(String nameSrvAddr, String clusterName, String topic,
+        int queueNum) {
+        int defaultWaitTime = 5;
+        return createTopic(nameSrvAddr, clusterName, topic, queueNum, defaultWaitTime);
+    }
+
+    public static boolean createTopic(String nameSrvAddr, String clusterName, String topic,
+        int queueNum, int waitTimeSec) {
+        boolean createResult = false;
+        DefaultMQAdminExt mqAdminExt = new DefaultMQAdminExt();
+        mqAdminExt.setNamesrvAddr(nameSrvAddr);
+        try {
+            mqAdminExt.start();
+            mqAdminExt.createTopic(clusterName, topic, queueNum);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        long startTime = System.currentTimeMillis();
+        while (!createResult) {
+            createResult = checkTopicExist(mqAdminExt, topic);
+            if (System.currentTimeMillis() - startTime < waitTimeSec * 1000) {
+                TestUtils.waitForMonment(100);
+            } else {
+                log.error(String.format("timeout,but create topic[%s] failed!", topic));
+                break;
+            }
+        }
+
+        mqAdminExt.shutdown();
+        return createResult;
+    }
+
+    private static boolean checkTopicExist(DefaultMQAdminExt mqAdminExt, String topic) {
+        boolean createResult = false;
+        try {
+            TopicStatsTable topicInfo = mqAdminExt.examineTopicStats(topic);
+            createResult = !topicInfo.getOffsetTable().isEmpty();
+        } catch (Exception e) {
+        }
+
+        return createResult;
+    }
+
+    public static boolean createSub(String nameSrvAddr, String clusterName, String consumerId) {
+        boolean createResult = true;
+        DefaultMQAdminExt mqAdminExt = new DefaultMQAdminExt();
+        mqAdminExt.setNamesrvAddr(nameSrvAddr);
+        SubscriptionGroupConfig config = new SubscriptionGroupConfig();
+        config.setGroupName(consumerId);
+        try {
+            mqAdminExt.start();
+            Set<String> masterSet = CommandUtil.fetchMasterAddrByClusterName(mqAdminExt,
+                clusterName);
+            for (String addr : masterSet) {
+                try {
+                    mqAdminExt.createAndUpdateSubscriptionGroupConfig(addr, config);
+                    log.info(String.format("create subscription group %s to %s success.\n", consumerId,
+                        addr));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    Thread.sleep(1000 * 1);
+                }
+            }
+        } catch (Exception e) {
+            createResult = false;
+            e.printStackTrace();
+        }
+        mqAdminExt.shutdown();
+        return createResult;
+    }
+
+    public static ClusterInfo getCluster(String nameSrvAddr) {
+        DefaultMQAdminExt mqAdminExt = new DefaultMQAdminExt();
+        mqAdminExt.setNamesrvAddr(nameSrvAddr);
+        ClusterInfo clusterInfo = null;
+        try {
+            mqAdminExt.start();
+            clusterInfo = mqAdminExt.examineBrokerClusterInfo();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        mqAdminExt.shutdown();
+        return clusterInfo;
+    }
+
+    public static boolean isBrokerExist(String ns, String ip) {
+        ClusterInfo clusterInfo = getCluster(ns);
+        if (clusterInfo == null) {
+            return false;
+        } else {
+            HashMap<String, BrokerData> brokers = clusterInfo.getBrokerAddrTable();
+            for (String brokerName : brokers.keySet()) {
+                HashMap<Long, String> brokerIps = brokers.get(brokerName).getBrokerAddrs();
+                for (long brokerId : brokerIps.keySet()) {
+                    if (brokerIps.get(brokerId).contains(ip))
+                        return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public void getSubConnection(String nameSrvAddr, String clusterName, String consumerId) {
+        boolean createResult = true;
+        DefaultMQAdminExt mqAdminExt = new DefaultMQAdminExt();
+        mqAdminExt.setNamesrvAddr(nameSrvAddr);
+        SubscriptionGroupConfig config = new SubscriptionGroupConfig();
+        config.setGroupName(consumerId);
+        try {
+            mqAdminExt.start();
+            Set<String> masterSet = CommandUtil.fetchMasterAddrByClusterName(mqAdminExt,
+                clusterName);
+            for (String addr : masterSet) {
+                try {
+
+                    System.out.printf("create subscription group %s to %s success.\n", consumerId,
+                        addr);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    Thread.sleep(1000 * 1);
+                }
+            }
+        } catch (Exception e) {
+            createResult = false;
+            e.printStackTrace();
+        }
+        mqAdminExt.shutdown();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/MQRandomUtils.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/MQRandomUtils.java b/test/src/main/java/org/apache/rocketmq/test/util/MQRandomUtils.java
new file mode 100644
index 0000000..1d82445
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/MQRandomUtils.java
@@ -0,0 +1,28 @@
+/*
+ * 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.rocketmq.test.util;
+
+public class MQRandomUtils {
+    public static String getRandomTopic() {
+        return RandomUtils.getStringByUUID();
+    }
+
+    public static String getRandomConsumerGroup() {
+        return RandomUtils.getStringByUUID();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/MQWait.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/MQWait.java b/test/src/main/java/org/apache/rocketmq/test/util/MQWait.java
new file mode 100644
index 0000000..6edeeca
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/MQWait.java
@@ -0,0 +1,93 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class MQWait {
+    private static Logger logger = Logger.getLogger(MQWait.class);
+
+    public static boolean waitConsumeAll(int timeoutMills, Collection<Object> allSendMsgs,
+        AbstractListener... listeners) {
+        boolean recvAll = false;
+        long startTime = System.currentTimeMillis();
+        Collection<Object> noDupMsgs = new ArrayList<Object>();
+        while (!recvAll) {
+            if ((System.currentTimeMillis() - startTime) < timeoutMills) {
+                noDupMsgs.clear();
+                try {
+                    for (AbstractListener listener : listeners) {
+                        Collection<Object> recvMsgs = Collections
+                            .synchronizedCollection(listener.getAllUndupMsgBody());
+                        noDupMsgs.addAll(VerifyUtils.getFilterdMessage(allSendMsgs, recvMsgs));
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+
+                try {
+                    assertThat(noDupMsgs).containsAllIn(allSendMsgs);
+                    recvAll = true;
+                    break;
+                } catch (Throwable e) {
+                }
+                TestUtil.waitForMonment(500);
+            } else {
+                logger.error(String.format(
+                    "timeout but still not receive all messages,expectSize[%s],realSize[%s]",
+                    allSendMsgs.size(), noDupMsgs.size()));
+                break;
+            }
+        }
+
+        return recvAll;
+    }
+
+    public static void setCondition(Condition condition, int waitTimeMills, int intervalMills) {
+        long startTime = System.currentTimeMillis();
+        while (!condition.meetCondition()) {
+            if (System.currentTimeMillis() - startTime > waitTimeMills) {
+                logger.error("time out,but contidion still not meet!");
+                break;
+            } else {
+                TestUtil.waitForMonment(intervalMills);
+            }
+        }
+    }
+
+    public static void main(String args[]) {
+
+        long start = System.currentTimeMillis();
+        MQWait.setCondition(new Condition() {
+            int i = 0;
+
+            public boolean meetCondition() {
+                i++;
+                return i == 100;
+            }
+        }, 10 * 1000, 200);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/RandomUtil.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/RandomUtil.java b/test/src/main/java/org/apache/rocketmq/test/util/RandomUtil.java
new file mode 100644
index 0000000..1c2bdac
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/RandomUtil.java
@@ -0,0 +1,306 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+public final class RandomUtil {
+
+    private static final int UNICODE_START = '\u4E00';
+    private static final int UNICODE_END = '\u9FA0';
+    private static Random rd = new Random();
+
+    private RandomUtil() {
+
+    }
+
+    public static long getLong() {
+        return rd.nextLong();
+    }
+
+    public static long getLongMoreThanZero() {
+        long res = rd.nextLong();
+        while (res <= 0) {
+            res = rd.nextLong();
+        }
+        return res;
+    }
+
+    public static long getLongLessThan(long n) {
+        long res = rd.nextLong();
+        return res % n;
+    }
+
+    public static long getLongMoreThanZeroLessThan(long n) {
+        long res = getLongLessThan(n);
+        while (res <= 0) {
+            res = getLongLessThan(n);
+        }
+        return res;
+    }
+
+    public static long getLongBetween(long n, long m) {
+        if (m <= n) {
+            return n;
+        }
+        long res = getLongMoreThanZero();
+        return n + res % (m - n);
+    }
+
+    public static int getInteger() {
+        return rd.nextInt();
+    }
+
+    public static int getIntegerMoreThanZero() {
+        int res = rd.nextInt();
+        while (res <= 0) {
+            res = rd.nextInt();
+        }
+        return res;
+    }
+
+    public static int getIntegerLessThan(int n) {
+        int res = rd.nextInt();
+        return res % n;
+    }
+
+    public static int getIntegerMoreThanZeroLessThan(int n) {
+        int res = rd.nextInt(n);
+        while (res == 0) {
+            res = rd.nextInt(n);
+        }
+        return res;
+    }
+
+    public static int getIntegerBetween(int n, int m)// m\ufffd\ufffd\u05b5\ufffd\ufffd\ufffd\ufffd\u03aa\ufffd\ufffd\ufffd\u0623\ufffd
+    {
+        if (m == n) {
+            return n;
+        }
+        int res = getIntegerMoreThanZero();
+        return n + res % (m - n);
+    }
+
+    private static char getChar(int arg[]) {
+        int size = arg.length;
+        int c = rd.nextInt(size / 2);
+        c = c * 2;
+        return (char) (getIntegerBetween(arg[c], arg[c + 1]));
+    }
+
+    private static String getString(int n, int arg[]) {
+        StringBuilder res = new StringBuilder();
+        for (int i = 0; i < n; i++) {
+            res.append(getChar(arg));
+        }
+        return res.toString();
+    }
+
+    public static String getStringWithCharacter(int n) {
+        int arg[] = new int[] {'a', 'z' + 1, 'A', 'Z' + 1};
+        return getString(n, arg);
+    }
+
+    public static String getStringWithNumber(int n) {
+        int arg[] = new int[] {'0', '9' + 1};
+        return getString(n, arg);
+    }
+
+    public static String getStringWithNumAndCha(int n) {
+        int arg[] = new int[] {'a', 'z' + 1, 'A', 'Z' + 1, '0', '9' + 1};
+        return getString(n, arg);
+    }
+
+    public static String getStringShortenThan(int n) {
+        int len = getIntegerMoreThanZeroLessThan(n);
+        return getStringWithCharacter(len);
+    }
+
+    public static String getStringWithNumAndChaShortenThan(int n) {
+        int len = getIntegerMoreThanZeroLessThan(n);
+        return getStringWithNumAndCha(len);
+    }
+
+    public static String getStringBetween(int n, int m) {
+        int len = getIntegerBetween(n, m);
+        return getStringWithCharacter(len);
+    }
+
+    public static String getStringWithNumAndChaBetween(int n, int m) {
+        int len = getIntegerBetween(n, m);
+        return getStringWithNumAndCha(len);
+    }
+
+    public static String getStringWithPrefix(int n, String prefix) {
+        int len = prefix.length();
+        if (n <= len)
+            return prefix;
+        else {
+            len = n - len;
+            StringBuilder res = new StringBuilder(prefix);
+            res.append(getStringWithCharacter(len));
+            return res.toString();
+        }
+    }
+
+    public static String getStringWithSuffix(int n, String suffix) {
+
+        int len = suffix.length();
+        if (n <= len)
+            return suffix;
+        else {
+            len = n - len;
+            StringBuilder res = new StringBuilder();
+            res.append(getStringWithCharacter(len));
+            res.append(suffix);
+            return res.toString();
+        }
+    }
+
+    public static String getStringWithBoth(int n, String prefix, String suffix) {
+        int len = prefix.length() + suffix.length();
+        StringBuilder res = new StringBuilder(prefix);
+        if (n <= len)
+            return res.append(suffix).toString();
+        else {
+            len = n - len;
+            res.append(getStringWithCharacter(len));
+            res.append(suffix);
+            return res.toString();
+        }
+    }
+
+    public static String getCheseWordWithPrifix(int n, String prefix) {
+        int len = prefix.length();
+        if (n <= len)
+            return prefix;
+        else {
+            len = n - len;
+            StringBuilder res = new StringBuilder(prefix);
+            res.append(getCheseWord(len));
+            return res.toString();
+        }
+    }
+
+    public static String getCheseWordWithSuffix(int n, String suffix) {
+
+        int len = suffix.length();
+        if (n <= len)
+            return suffix;
+        else {
+            len = n - len;
+            StringBuilder res = new StringBuilder();
+            res.append(getCheseWord(len));
+            res.append(suffix);
+            return res.toString();
+        }
+    }
+
+    public static String getCheseWordWithBoth(int n, String prefix, String suffix) {
+        int len = prefix.length() + suffix.length();
+        StringBuilder res = new StringBuilder(prefix);
+        if (n <= len)
+            return res.append(suffix).toString();
+        else {
+            len = n - len;
+            res.append(getCheseWord(len));
+            res.append(suffix);
+            return res.toString();
+        }
+    }
+
+    public static String getCheseWord(int len) {
+        StringBuilder res = new StringBuilder();
+        for (int i = 0; i < len; i++) {
+            char str = getCheseChar();
+            res.append(str);
+        }
+        return res.toString();
+    }
+
+    private static char getCheseChar() {
+        return (char) (UNICODE_START + rd.nextInt(UNICODE_END - UNICODE_START));
+    }
+
+    public static boolean getBoolean() {
+        return getIntegerMoreThanZeroLessThan(3) == 1;
+    }
+
+    public static String getStringByUUID() {
+        return UUID.randomUUID().toString();
+    }
+
+    public static int[] getRandomArray(int min, int max, int n) {
+        int len = max - min + 1;
+
+        if (max < min || n > len) {
+            return null;
+        }
+
+        int[] source = new int[len];
+        for (int i = min; i < min + len; i++) {
+            source[i - min] = i;
+        }
+
+        int[] result = new int[n];
+        Random rd = new Random();
+        int index = 0;
+        for (int i = 0; i < result.length; i++) {
+            index = Math.abs(rd.nextInt() % len--);
+            result[i] = source[index];
+            source[index] = source[len];
+        }
+        return result;
+    }
+
+    public static Collection<Integer> getRandomCollection(int min, int max, int n) {
+        Set<Integer> res = new HashSet<Integer>();
+        int mx = max;
+        int mn = min;
+        if (n == (max + 1 - min)) {
+            for (int i = 1; i <= n; i++) {
+                res.add(i);
+            }
+            return res;
+        }
+        for (int i = 0; i < n; i++) {
+            int v = getIntegerBetween(mn, mx);
+            if (v == mx) {
+                mx--;
+            }
+            if (v == mn) {
+                mn++;
+            }
+            while (res.contains(v)) {
+                v = getIntegerBetween(mn, mx);
+                if (v == mx) {
+                    mx = v;
+                }
+                if (v == mn) {
+                    mn = v;
+                }
+            }
+            res.add(v);
+        }
+        return res;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/RandomUtils.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/RandomUtils.java b/test/src/main/java/org/apache/rocketmq/test/util/RandomUtils.java
new file mode 100644
index 0000000..9eca28b
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/RandomUtils.java
@@ -0,0 +1,91 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.util.Random;
+import java.util.UUID;
+
+public class RandomUtils {
+    private static final int UNICODE_START = '\u4E00';
+    private static final int UNICODE_END = '\u9FA0';
+    private static Random rd = new Random();
+
+    private RandomUtils() {
+
+    }
+
+    public static String getStringByUUID() {
+        return UUID.randomUUID().toString();
+    }
+
+    public static String getCheseWord(int len) {
+        StringBuilder res = new StringBuilder();
+
+        for (int i = 0; i < len; ++i) {
+            char str = getCheseChar();
+            res.append(str);
+        }
+
+        return res.toString();
+    }
+
+    public static String getStringWithNumber(int n) {
+        int arg[] = new int[] {'0', '9' + 1};
+        return getString(n, arg);
+    }
+
+    public static String getStringWithCharacter(int n) {
+        int arg[] = new int[] {'a', 'z' + 1, 'A', 'Z' + 1};
+        return getString(n, arg);
+    }
+
+    private static String getString(int n, int arg[]) {
+        StringBuilder res = new StringBuilder();
+        for (int i = 0; i < n; i++) {
+            res.append(getChar(arg));
+        }
+        return res.toString();
+    }
+
+    private static char getChar(int arg[]) {
+        int size = arg.length;
+        int c = rd.nextInt(size / 2);
+        c = c * 2;
+        return (char) (getIntegerBetween(arg[c], arg[c + 1]));
+    }
+
+    public static int getIntegerBetween(int n, int m) {
+        if (m == n) {
+            return n;
+        }
+        int res = getIntegerMoreThanZero();
+        return n + res % (m - n);
+    }
+
+    public static int getIntegerMoreThanZero() {
+        int res = rd.nextInt();
+        while (res <= 0) {
+            res = rd.nextInt();
+        }
+        return res;
+    }
+
+    private static char getCheseChar() {
+        return (char) (UNICODE_START + rd.nextInt(UNICODE_END - UNICODE_START));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/TestUtil.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/TestUtil.java b/test/src/main/java/org/apache/rocketmq/test/util/TestUtil.java
new file mode 100644
index 0000000..591b3b7
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/TestUtil.java
@@ -0,0 +1,122 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public final class TestUtil {
+
+    private TestUtil() {
+    }
+
+    public static Long parseStringToLong(String s, Long defval) {
+        Long val = defval;
+        try {
+            val = Long.parseLong(s);
+        } catch (NumberFormatException e) {
+            val = defval;
+        }
+        return val;
+    }
+
+    public static Integer parseStringToInteger(String s, Integer defval) {
+        Integer val = defval;
+        try {
+            val = Integer.parseInt(s);
+        } catch (NumberFormatException e) {
+            val = defval;
+        }
+        return val;
+    }
+
+    public static String addQuoteToParamater(String param) {
+        StringBuilder sb = new StringBuilder("'");
+        sb.append(param).append("'");
+        return sb.toString();
+    }
+
+    public static void waitForMonment(long time) {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void waitForSeconds(long time) {
+        try {
+            TimeUnit.SECONDS.sleep(time);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void waitForMinutes(long time) {
+        try {
+            TimeUnit.MINUTES.sleep(time);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void waitForInputQuit() {
+        waitForInput("quit");
+    }
+
+    public static void waitForInput(String keyWord) {
+        waitForInput(keyWord,
+            String.format("The thread will wait until you input stop command[%s]:", keyWord));
+    }
+
+    public static void waitForInput(String keyWord, String info) {
+        try {
+            byte[] b = new byte[1024];
+            int n = System.in.read(b);
+            String s = new String(b, 0, n - 1).replace("\r", "").replace("\n", "");
+            while (!s.equals(keyWord)) {
+                n = System.in.read(b);
+                s = new String(b, 0, n - 1);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
+        List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet());
+        Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
+            public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
+                return (o1.getValue()).compareTo(o2.getValue());
+            }
+        });
+
+        Map<K, V> result = new LinkedHashMap<K, V>();
+        for (Map.Entry<K, V> entry : list) {
+            result.put(entry.getKey(), entry.getValue());
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/TestUtils.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/TestUtils.java b/test/src/main/java/org/apache/rocketmq/test/util/TestUtils.java
new file mode 100644
index 0000000..6326d46
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/TestUtils.java
@@ -0,0 +1,50 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.util.concurrent.TimeUnit;
+
+public class TestUtils {
+    public static void waitForMonment(long time) {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException var3) {
+            var3.printStackTrace();
+        }
+
+    }
+
+    public static void waitForSeconds(long time) {
+        try {
+            TimeUnit.SECONDS.sleep(time);
+        } catch (InterruptedException var3) {
+            var3.printStackTrace();
+        }
+
+    }
+
+    public static void waitForMinutes(long time) {
+        try {
+            TimeUnit.MINUTES.sleep(time);
+        } catch (InterruptedException var3) {
+            var3.printStackTrace();
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/VerifyUtils.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/VerifyUtils.java b/test/src/main/java/org/apache/rocketmq/test/util/VerifyUtils.java
new file mode 100644
index 0000000..965d2ee
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/VerifyUtils.java
@@ -0,0 +1,146 @@
+/*
+ * 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.rocketmq.test.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageExt;
+
+public class VerifyUtils {
+    private static Logger logger = Logger.getLogger(VerifyUtils.class);
+
+    public static int verify(Collection<Object> sendMsgs, Collection<Object> recvMsgs) {
+        int miss = 0;
+        for (Object msg : sendMsgs) {
+            if (!recvMsgs.contains(msg)) {
+                miss++;
+            }
+        }
+
+        return miss;
+    }
+
+    public static Collection<Object> getFilterdMessage(Collection<Object> sendMsgs,
+        Collection<Object> recvMsgs) {
+        Collection<Object> recvMsgsSync = Collections.synchronizedCollection(recvMsgs);
+        Collection<Object> filterdMsgs = new ArrayList<Object>();
+        int filterNum = 0;
+        for (Object msg : recvMsgsSync) {
+            if (sendMsgs.contains(msg)) {
+                filterdMsgs.add(msg);
+            } else {
+                filterNum++;
+            }
+        }
+
+        logger.info(String.format("[%s] messages is filterd!", filterNum));
+        return filterdMsgs;
+    }
+
+    public static int verifyUserProperty(Collection<Object> sendMsgs, Collection<Object> recvMsgs) {
+        return 0;
+    }
+
+    public static void verifyMessageQueueId(int expectId, Collection<Object> msgs) {
+        for (Object msg : msgs) {
+            MessageExt msgEx = (MessageExt) msg;
+            assert expectId == msgEx.getQueueId();
+        }
+    }
+
+    public static boolean verifyBalance(int msgSize, float error, int... recvSize) {
+        boolean balance = true;
+        int evenSize = msgSize / recvSize.length;
+        for (int size : recvSize) {
+            if (Math.abs(size - evenSize) > error * evenSize) {
+                balance = false;
+                break;
+            }
+        }
+        return balance;
+    }
+
+    public static boolean verifyBalance(int msgSize, int... recvSize) {
+        return verifyBalance(msgSize, 0.1f, recvSize);
+    }
+
+    public static boolean verifyDelay(long delayTimeMills, Collection<Object> recvMsgTimes,
+        int errorMills) {
+        boolean delay = true;
+        for (Object timeObj : recvMsgTimes) {
+            long time = (Long) timeObj;
+            if (Math.abs(time - delayTimeMills) > errorMills) {
+                delay = false;
+                logger.info(String.format("delay error:%s", Math.abs(time - delayTimeMills)));
+            }
+        }
+        return delay;
+    }
+
+    public static boolean verifyDelay(long delayTimeMills, Collection<Object> recvMsgTimes) {
+        int errorMills = 500;
+        return verifyDelay(delayTimeMills, recvMsgTimes, errorMills);
+    }
+
+    public static boolean verifyOrder(Collection<Collection<Object>> queueMsgs) {
+        for (Collection<Object> msgs : queueMsgs) {
+            if (!verifyOrderMsg(msgs)) {
+                return false;
+            }
+        }
+        return true;
+
+    }
+
+    public static boolean verifyOrderMsg(Collection<Object> msgs) {
+        int min = Integer.MIN_VALUE;
+        int curr;
+        if (msgs.size() == 0 || msgs.size() == 1) {
+            return true;
+        } else {
+            for (Object msg : msgs) {
+                curr = Integer.parseInt((String) msg);
+                if (curr < min) {
+                    return false;
+                } else {
+                    min = curr;
+                }
+            }
+        }
+        return true;
+    }
+
+    public static boolean verifyRT(Collection<Object> rts, long maxRTMills) {
+        boolean rtExpect = true;
+        for (Object obj : rts) {
+            long rt = (Long) obj;
+            if (rt > maxRTMills) {
+                rtExpect = false;
+                logger.info(String.format("%s greater thran maxtRT:%s!", rt, maxRTMills));
+
+            }
+        }
+        return rtExpect;
+    }
+
+    public static void main(String args[]) {
+        verifyBalance(400, 0.1f, 230, 190);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollector.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollector.java b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollector.java
new file mode 100644
index 0000000..cbbc8a5
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollector.java
@@ -0,0 +1,45 @@
+/*
+ * 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.rocketmq.test.util.data.collect;
+
+import java.util.Collection;
+
+public interface DataCollector {
+
+    void resetData();
+
+    Collection<Object> getAllData();
+
+    Collection<Object> getAllDataWithoutDuplicate();
+
+    void addData(Object data);
+
+    long getDataSizeWithoutDuplicate();
+
+    long getDataSize();
+
+    boolean isRepeatedData(Object data);
+
+    int getRepeatedTimeForData(Object data);
+
+    void removeData(Object data);
+
+    void lockIncrement();
+
+    void unlockIncrement();
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollectorManager.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollectorManager.java b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollectorManager.java
new file mode 100644
index 0000000..47f4d81
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataCollectorManager.java
@@ -0,0 +1,112 @@
+/*
+ * 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.rocketmq.test.util.data.collect;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.rocketmq.test.util.data.collect.impl.ListDataCollectorImpl;
+import org.apache.rocketmq.test.util.data.collect.impl.MapDataCollectorImpl;
+
+public final class DataCollectorManager {
+    private static DataCollectorManager instance = new DataCollectorManager();
+    private Map<String, DataCollector> collectMap = new HashMap<String, DataCollector>();
+    private Object lock = new Object();
+
+    private DataCollectorManager() {
+    }
+
+    public static DataCollectorManager getInstance() {
+        return instance;
+    }
+
+    public DataCollector fetchDataCollector(String key) {
+        String realKey = key;
+        if (!collectMap.containsKey(realKey)) {
+            synchronized (lock) {
+                if (!collectMap.containsKey(realKey)) {
+                    DataCollector collect = (DataCollector) new MapDataCollectorImpl();
+                    collectMap.put(realKey, collect);
+                }
+            }
+        }
+        return collectMap.get(realKey);
+    }
+
+    public DataCollector fetchMapDataCollector(String key) {
+        String realKey = key;
+        if (!collectMap.containsKey(realKey)
+            || collectMap.get(realKey) instanceof ListDataCollectorImpl) {
+            synchronized (lock) {
+                if (!collectMap.containsKey(realKey)
+                    || collectMap.get(realKey) instanceof ListDataCollectorImpl) {
+                    DataCollector collect = null;
+                    if (collectMap.containsKey(realKey)) {
+                        DataCollector src = collectMap.get(realKey);
+                        collect = new MapDataCollectorImpl(src.getAllData());
+                    } else {
+                        collect = new MapDataCollectorImpl();
+                    }
+                    collectMap.put(realKey, collect);
+
+                }
+            }
+        }
+        return collectMap.get(realKey);
+    }
+
+    public DataCollector fetchListDataCollector(String key) {
+        String realKey = key;
+        if (!collectMap.containsKey(realKey)
+            || collectMap.get(realKey) instanceof MapDataCollectorImpl) {
+            synchronized (lock) {
+                if (!collectMap.containsKey(realKey)
+                    || collectMap.get(realKey) instanceof MapDataCollectorImpl) {
+                    DataCollector collect = null;
+                    if (collectMap.containsKey(realKey)) {
+                        DataCollector src = collectMap.get(realKey);
+                        collect = new ListDataCollectorImpl(src.getAllData());
+                    } else {
+                        collect = new ListDataCollectorImpl();
+                    }
+                    collectMap.put(realKey, collect);
+                }
+            }
+        }
+        return collectMap.get(realKey);
+    }
+
+    public void resetDataCollect(String key) {
+        if (collectMap.containsKey(key)) {
+            collectMap.get(key).resetData();
+        }
+    }
+
+    public void resetAll() {
+        for (Map.Entry<String, DataCollector> entry : collectMap.entrySet()) {
+            entry.getValue().resetData();
+        }
+    }
+
+    public void removeDataCollect(String key) {
+        collectMap.remove(key);
+    }
+
+    public void removeAll() {
+        collectMap.clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataFilter.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataFilter.java b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataFilter.java
new file mode 100644
index 0000000..b01adc5
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/DataFilter.java
@@ -0,0 +1,22 @@
+/*
+ * 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.rocketmq.test.util.data.collect;
+
+public interface DataFilter {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/ListDataCollectorImpl.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/ListDataCollectorImpl.java b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/ListDataCollectorImpl.java
new file mode 100644
index 0000000..82ab461
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/ListDataCollectorImpl.java
@@ -0,0 +1,95 @@
+/*
+ * 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.rocketmq.test.util.data.collect.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import org.apache.rocketmq.test.util.data.collect.DataCollector;
+
+public class ListDataCollectorImpl implements DataCollector {
+
+    private List<Object> datas = new ArrayList<Object>();
+    private boolean lock = false;
+
+    public ListDataCollectorImpl() {
+
+    }
+
+    public ListDataCollectorImpl(Collection<Object> datas) {
+        for (Object data : datas) {
+            addData(data);
+        }
+    }
+
+    public Collection<Object> getAllData() {
+        return datas;
+    }
+
+    public void resetData() {
+        datas.clear();
+        unlockIncrement();
+    }
+
+    public long getDataSizeWithoutDuplicate() {
+        return getAllDataWithoutDuplicate().size();
+    }
+
+    public synchronized void addData(Object data) {
+        if (lock) {
+            return;
+        }
+        datas.add(data);
+    }
+
+    public long getDataSize() {
+        return datas.size();
+    }
+
+    public boolean isRepeatedData(Object data) {
+        return Collections.frequency(datas, data) == 1;
+    }
+
+    public Collection<Object> getAllDataWithoutDuplicate() {
+        return new HashSet<Object>(datas);
+    }
+
+    public int getRepeatedTimeForData(Object data) {
+        int res = 0;
+        for (Object obj : datas) {
+            if (obj.equals(data)) {
+                res++;
+            }
+        }
+        return res;
+    }
+
+    public void removeData(Object data) {
+        datas.remove(data);
+    }
+
+    public void lockIncrement() {
+        lock = true;
+    }
+
+    public void unlockIncrement() {
+        lock = false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/MapDataCollectorImpl.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/MapDataCollectorImpl.java b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/MapDataCollectorImpl.java
new file mode 100644
index 0000000..899bb85
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/data/collect/impl/MapDataCollectorImpl.java
@@ -0,0 +1,111 @@
+/*
+ * 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.rocketmq.test.util.data.collect.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.rocketmq.test.util.data.collect.DataCollector;
+
+public class MapDataCollectorImpl implements DataCollector {
+
+    private Map<Object, AtomicInteger> datas = new ConcurrentHashMap<Object, AtomicInteger>();
+    private boolean lock = false;
+
+    public MapDataCollectorImpl() {
+
+    }
+
+    public MapDataCollectorImpl(Collection<Object> datas) {
+        for (Object data : datas) {
+            addData(data);
+        }
+    }
+
+    public synchronized void addData(Object data) {
+        if (lock) {
+            return;
+        }
+        if (datas.containsKey(data)) {
+            datas.get(data).addAndGet(1);
+        } else {
+            datas.put(data, new AtomicInteger(1));
+        }
+    }
+
+    public Collection<Object> getAllData() {
+        List<Object> lst = new ArrayList<Object>();
+        for (Entry<Object, AtomicInteger> entry : datas.entrySet()) {
+            for (int i = 0; i < entry.getValue().get(); i++) {
+                lst.add(entry.getKey());
+            }
+        }
+        return lst;
+    }
+
+    public long getDataSizeWithoutDuplicate() {
+        return datas.keySet().size();
+    }
+
+    public void resetData() {
+        datas.clear();
+        unlockIncrement();
+    }
+
+    public long getDataSize() {
+        long sum = 0;
+        for (AtomicInteger count : datas.values()) {
+            sum = sum + count.get();
+        }
+        return sum;
+    }
+
+    public boolean isRepeatedData(Object data) {
+        if (datas.containsKey(data)) {
+            return datas.get(data).get() == 1;
+        }
+        return false;
+    }
+
+    public Collection<Object> getAllDataWithoutDuplicate() {
+        return datas.keySet();
+    }
+
+    public int getRepeatedTimeForData(Object data) {
+        if (datas.containsKey(data)) {
+            return datas.get(data).intValue();
+        }
+        return 0;
+    }
+
+    public void removeData(Object data) {
+        datas.remove(data);
+    }
+
+    public void lockIncrement() {
+        lock = true;
+    }
+
+    public void unlockIncrement() {
+        lock = false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTask.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTask.java b/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTask.java
new file mode 100644
index 0000000..a4ad9a8
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTask.java
@@ -0,0 +1,43 @@
+/*
+ * 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.rocketmq.test.util.parallel;
+
+import java.util.concurrent.CountDownLatch;
+
+public abstract class ParallelTask extends Thread {
+    private CountDownLatch latch = null;
+
+    public CountDownLatch getLatch() {
+        return latch;
+    }
+
+    public void setLatch(CountDownLatch latch) {
+        this.latch = latch;
+    }
+
+    public abstract void execute();
+
+    @Override
+    public void run() {
+        this.execute();
+
+        if (latch != null) {
+            latch.countDown();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTaskExecutor.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTaskExecutor.java b/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTaskExecutor.java
new file mode 100644
index 0000000..e7e9209
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/parallel/ParallelTaskExecutor.java
@@ -0,0 +1,67 @@
+/*
+ * 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.rocketmq.test.util.parallel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ParallelTaskExecutor {
+    public List<ParallelTask> tasks = new ArrayList<ParallelTask>();
+    public ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
+    public CountDownLatch latch = null;
+
+    public ParallelTaskExecutor() {
+
+    }
+
+    public void pushTask(ParallelTask task) {
+        tasks.add(task);
+    }
+
+    public void startBlock() {
+        init();
+        startTask();
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void startNoBlock() {
+        for (ParallelTask task : tasks) {
+            cachedThreadPool.execute(task);
+        }
+    }
+
+    private void init() {
+        latch = new CountDownLatch(tasks.size());
+        for (ParallelTask task : tasks) {
+            task.setLatch(latch);
+        }
+    }
+
+    private void startTask() {
+        for (ParallelTask task : tasks) {
+            task.start();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/main/java/org/apache/rocketmq/test/util/parallel/Task4Test.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/parallel/Task4Test.java b/test/src/main/java/org/apache/rocketmq/test/util/parallel/Task4Test.java
new file mode 100644
index 0000000..c168d66
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/util/parallel/Task4Test.java
@@ -0,0 +1,30 @@
+/*
+ * 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.rocketmq.test.util.parallel;
+
+public class Task4Test extends ParallelTask {
+    private String name = "";
+
+    public Task4Test(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void execute() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java
new file mode 100644
index 0000000..57462a2
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java
@@ -0,0 +1,162 @@
+/*
+ * 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.rocketmq.test.base;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.namesrv.NamesrvController;
+import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.clientinterface.AbstractMQConsumer;
+import org.apache.rocketmq.test.clientinterface.AbstractMQProducer;
+import org.apache.rocketmq.test.factory.ConsumerFactory;
+import org.apache.rocketmq.test.listener.AbstractListener;
+import org.apache.rocketmq.test.util.MQAdmin;
+import org.apache.rocketmq.test.util.MQRandomUtils;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.junit.Assert;
+
+public class BaseConf {
+    protected static String nsAddr;
+    protected static String broker1Name;
+    protected static String broker2Name;
+    protected static String clusterName;
+    protected static int brokerNum;
+    protected static int waitTime = 5;
+    protected static int consumeTime = 1 * 60 * 1000;
+    protected static int topicCreateTime = 30 * 1000;
+    protected static NamesrvController namesrvController;
+    protected static BrokerController brokerController1;
+    protected static BrokerController brokerController2;
+    protected static List<Object> mqClients = new ArrayList<Object>();
+    protected static boolean debug = false;
+    private static Logger log = Logger.getLogger(BaseConf.class);
+
+    static {
+        namesrvController = IntegrationTestBase.createAndStartNamesrv();
+        nsAddr = "127.0.0.1:" + namesrvController.getNettyServerConfig().getListenPort();
+        brokerController1 = IntegrationTestBase.createAndStartBroker(nsAddr);
+        brokerController2 = IntegrationTestBase.createAndStartBroker(nsAddr);
+        clusterName = brokerController1.getBrokerConfig().getBrokerClusterName();
+        broker1Name = brokerController1.getBrokerConfig().getBrokerName();
+        broker2Name = brokerController2.getBrokerConfig().getBrokerName();
+        brokerNum = 2;
+    }
+
+    public BaseConf() {
+
+    }
+
+    public static String initTopic() {
+        long startTime = System.currentTimeMillis();
+        String topic = MQRandomUtils.getRandomTopic();
+        boolean createResult = false;
+        while (true) {
+            createResult = MQAdmin.createTopic(nsAddr, clusterName, topic, 8);
+            if (createResult) {
+                break;
+            } else if (System.currentTimeMillis() - startTime > topicCreateTime) {
+                Assert.fail(String.format("topic[%s] is created failed after:%d ms", topic,
+                    System.currentTimeMillis() - startTime));
+                break;
+            } else {
+                TestUtils.waitForMonment(500);
+                continue;
+            }
+        }
+
+        return topic;
+    }
+
+    public static String initConsumerGroup() {
+        String group = MQRandomUtils.getRandomConsumerGroup();
+        return initConsumerGroup(group);
+    }
+
+    public static String initConsumerGroup(String group) {
+        MQAdmin.createSub(nsAddr, clusterName, group);
+        return group;
+    }
+
+    public static RMQNormalProducer getProducer(String nsAddr, String topic) {
+        RMQNormalProducer producer = new RMQNormalProducer(nsAddr, topic);
+        if (debug) {
+            producer.setDebug();
+        }
+        mqClients.add(producer);
+        return producer;
+    }
+
+    public static RMQNormalProducer getProducer(String nsAddr, String topic, String producerGoup,
+        String instanceName) {
+        RMQNormalProducer producer = new RMQNormalProducer(nsAddr, topic, producerGoup,
+            instanceName);
+        if (debug) {
+            producer.setDebug();
+        }
+        mqClients.add(producer);
+        return producer;
+    }
+
+    public static RMQAsyncSendProducer getAsyncProducer(String nsAddr, String topic) {
+        RMQAsyncSendProducer producer = new RMQAsyncSendProducer(nsAddr, topic);
+        if (debug) {
+            producer.setDebug();
+        }
+        mqClients.add(producer);
+        return producer;
+    }
+
+    public static RMQNormalConsumer getConsumer(String nsAddr, String topic, String subExpression,
+        AbstractListener listner) {
+        String consumerGroup = initConsumerGroup();
+        return getConsumer(nsAddr, consumerGroup, topic, subExpression, listner);
+    }
+
+    public static RMQNormalConsumer getConsumer(String nsAddr, String consumerGroup, String topic,
+        String subExpression, AbstractListener listner) {
+        RMQNormalConsumer consumer = ConsumerFactory.getRMQNormalConsumer(nsAddr, consumerGroup,
+            topic, subExpression, listner);
+        if (debug) {
+            consumer.setDebug();
+        }
+        mqClients.add(consumer);
+        log.info(String.format("consumer[%s] start,topic[%s],subExpression[%s]", consumerGroup,
+            topic, subExpression));
+        return consumer;
+    }
+
+    public static void shutDown() {
+        try {
+            for (Object mqClient : mqClients) {
+                if (mqClient instanceof AbstractMQProducer) {
+                    ((AbstractMQProducer) mqClient).shutdown();
+
+                } else {
+                    ((AbstractMQConsumer) mqClient).shutdown();
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
new file mode 100644
index 0000000..ff9996d
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
@@ -0,0 +1,143 @@
+/*
+ * 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.rocketmq.test.base;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.namesrv.NamesrvConfig;
+import org.apache.rocketmq.namesrv.NamesrvController;
+import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.junit.Assert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class IntegrationTestBase {
+    protected static final String SEP = File.separator;
+    protected static final String BROKER_NAME_PREFIX = "TestBrokerName_";
+    protected static final AtomicInteger BROKER_INDEX = new AtomicInteger(0);
+    protected static final List<File> TMPE_FILES = new ArrayList<>();
+    protected static final List<BrokerController> BROKER_CONTROLLERS = new ArrayList<>();
+    protected static final List<NamesrvController> NAMESRV_CONTROLLERS = new ArrayList<>();
+    public static Logger logger = LoggerFactory.getLogger(IntegrationTestBase.class);
+    protected static Random random = new Random();
+
+    static {
+
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override public void run() {
+                for (NamesrvController namesrvController : NAMESRV_CONTROLLERS) {
+                    if (namesrvController != null) {
+                        namesrvController.shutdown();
+                    }
+                }
+                for (BrokerController brokerController : BROKER_CONTROLLERS) {
+                    if (brokerController != null) {
+                        brokerController.shutdown();
+                    }
+                }
+                for (File file : TMPE_FILES) {
+                    deleteFile(file);
+                }
+            }
+        });
+
+    }
+
+    private static String createBaseDir() {
+        String baseDir = System.getProperty("user.home") + SEP + "unitteststore-" + UUID.randomUUID();
+        final File file = new File(baseDir);
+        if (file.exists()) {
+            logger.info(String.format("[%s] has already existed, please bake up and remove it for integration tests", baseDir));
+            System.exit(1);
+        }
+        TMPE_FILES.add(file);
+        return baseDir;
+    }
+
+    public static NamesrvController createAndStartNamesrv() {
+        String baseDir = createBaseDir();
+        NamesrvConfig namesrvConfig = new NamesrvConfig();
+        NettyServerConfig nameServerNettyServerConfig = new NettyServerConfig();
+        namesrvConfig.setKvConfigPath(baseDir + SEP + "namesrv" + SEP + "kvConfig.json");
+        namesrvConfig.setConfigStorePath(baseDir + SEP + "namesrv" + SEP + "namesrv.properties");
+
+        nameServerNettyServerConfig.setListenPort(9000 + random.nextInt(1000));
+        NamesrvController namesrvController = new NamesrvController(namesrvConfig, nameServerNettyServerConfig);
+        try {
+            Assert.assertTrue(namesrvController.initialize());
+            logger.info("Name Server Start:{}", nameServerNettyServerConfig.getListenPort());
+            namesrvController.start();
+        } catch (Exception e) {
+            logger.info("Name Server start failed");
+            System.exit(1);
+        }
+        NAMESRV_CONTROLLERS.add(namesrvController);
+        return namesrvController;
+
+    }
+
+    public static BrokerController createAndStartBroker(String nsAddr) {
+        String baseDir = createBaseDir();
+        BrokerConfig brokerConfig = new BrokerConfig();
+        NettyServerConfig nettyServerConfig = new NettyServerConfig();
+        NettyClientConfig nettyClientConfig = new NettyClientConfig();
+        MessageStoreConfig storeConfig = new MessageStoreConfig();
+        brokerConfig.setBrokerName(BROKER_NAME_PREFIX + BROKER_INDEX.getAndIncrement());
+        brokerConfig.setBrokerIP1("127.0.0.1");
+        brokerConfig.setNamesrvAddr(nsAddr);
+        storeConfig.setStorePathRootDir(baseDir);
+        storeConfig.setStorePathCommitLog(baseDir + SEP + "commitlog");
+        storeConfig.setHaListenPort(8000 + random.nextInt(1000));
+        nettyServerConfig.setListenPort(10000 + random.nextInt(1000));
+        BrokerController brokerController = new BrokerController(brokerConfig, nettyServerConfig, nettyClientConfig, storeConfig);
+        try {
+            Assert.assertTrue(brokerController.initialize());
+            logger.info("Broker Start name:{} addr:{}", brokerConfig.getBrokerName(), brokerController.getBrokerAddr());
+            brokerController.start();
+        } catch (Exception e) {
+            logger.info("Broker start failed");
+            System.exit(1);
+        }
+        BROKER_CONTROLLERS.add(brokerController);
+        return brokerController;
+    }
+
+    public static void deleteFile(File file) {
+        if (!file.exists()) {
+            return;
+        }
+        if (file.isFile()) {
+            file.delete();
+        } else if (file.isDirectory()) {
+            File[] files = file.listFiles();
+            for (File file1 : files) {
+                deleteFile(file1);
+            }
+            file.delete();
+        }
+    }
+
+}



[06/13] incubator-rocketmq git commit: [RocketMQ-58] Add integration test for RocketMQ, also thanks @fenglianghfl for this commit, closes apache/incubator-rocketmq#46

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithMulConsumerIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithMulConsumerIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithMulConsumerIT.java
new file mode 100644
index 0000000..995bf41
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithMulConsumerIT.java
@@ -0,0 +1,196 @@
+/*
+ * 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.rocketmq.test.client.consumer.tag;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.factory.TagMessage;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class TagMessageWithMulConsumerIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        String consumerId = initConsumerGroup();
+        logger.info(String.format("use topic: %s; consumerId: %s !", topic, consumerId));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSendTwoTag() {
+        String tag1 = "jueyin1";
+        String tag2 = "jueyin2";
+        int msgSize = 10;
+        RMQNormalConsumer consumerTag1 = getConsumer(nsAddr, topic, tag1,
+            new RMQNormalListner());
+        RMQNormalConsumer consumerTag2 = getConsumer(nsAddr, topic, tag2,
+            new RMQNormalListner());
+
+        List<Object> tag1Msgs = MQMessageFactory.getRMQMessage(tag1, topic, msgSize);
+        producer.send(tag1Msgs);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        List<Object> tag2Msgs = MQMessageFactory.getRMQMessage(tag2, topic, msgSize);
+        producer.send(tag2Msgs);
+        Assert.assertEquals("Not all are sent", msgSize * 2, producer.getAllUndupMsgBody().size());
+
+        consumerTag1.getListner().waitForMessageConsume(MQMessageFactory.getMessageBody(tag1Msgs),
+            consumeTime);
+        consumerTag2.getListner().waitForMessageConsume(MQMessageFactory.getMessageBody(tag2Msgs),
+            consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerTag1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(MQMessageFactory.getMessageBody(tag1Msgs));
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerTag2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(MQMessageFactory.getMessageBody(tag2Msgs));
+    }
+
+    @Test
+    public void testSendMessagesWithTwoTag() {
+        String tags[] = {"jueyin1", "jueyin2"};
+        int msgSize = 10;
+
+        TagMessage tagMessage = new TagMessage(tags, topic, msgSize);
+        RMQNormalConsumer consumerTag1 = getConsumer(nsAddr, topic, tags[0],
+            new RMQNormalListner());
+        RMQNormalConsumer consumerTag2 = getConsumer(nsAddr, topic, tags[1],
+            new RMQNormalListner());
+
+        List<Object> tagMsgs = tagMessage.getMixedTagMessages();
+        producer.send(tagMsgs);
+        Assert.assertEquals("Not all are sent", msgSize * tags.length,
+            producer.getAllUndupMsgBody().size());
+
+        consumerTag1.getListner().waitForMessageConsume(tagMessage.getMessageBodyByTag(tags[0]),
+            consumeTime);
+        consumerTag2.getListner().waitForMessageConsume(tagMessage.getMessageBodyByTag(tags[1]),
+            consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerTag1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getMessageBodyByTag(tags[0]));
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerTag2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getMessageBodyByTag(tags[1]));
+    }
+
+    @Test
+    public void testTwoConsumerOneMatchOneOtherMatchAll() {
+        String tags[] = {"jueyin1", "jueyin2"};
+        String sub1 = String.format("%s||%s", tags[0], tags[1]);
+        String sub2 = String.format("%s|| noExist", tags[0]);
+        int msgSize = 10;
+
+        TagMessage tagMessage = new TagMessage(tags, topic, msgSize);
+        RMQNormalConsumer consumerTag1 = getConsumer(nsAddr, topic, sub1,
+            new RMQNormalListner());
+        RMQNormalConsumer consumerTag2 = getConsumer(nsAddr, topic, sub2,
+            new RMQNormalListner());
+
+        List<Object> tagMsgs = tagMessage.getMixedTagMessages();
+        producer.send(tagMsgs);
+        Assert.assertEquals("Not all are sent", msgSize * tags.length,
+            producer.getAllUndupMsgBody().size());
+
+        consumerTag1.getListner().waitForMessageConsume(tagMessage.getMessageBodyByTag(tags),
+            consumeTime);
+        consumerTag2.getListner().waitForMessageConsume(tagMessage.getMessageBodyByTag(tags[0]),
+            consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerTag1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getAllTagMessageBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerTag2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getMessageBodyByTag(tags[0]));
+    }
+
+    @Test
+    public void testSubKindsOf() {
+        String tags[] = {"jueyin1", "jueyin2"};
+        String sub1 = String.format("%s||%s", tags[0], tags[1]);
+        String sub2 = String.format("%s|| noExist", tags[0]);
+        String sub3 = tags[0];
+        String sub4 = "*";
+        int msgSize = 10;
+
+        RMQNormalConsumer consumerSubTwoMatchAll = getConsumer(nsAddr, topic, sub1,
+            new RMQNormalListner());
+        RMQNormalConsumer consumerSubTwoMachieOne = getConsumer(nsAddr, topic, sub2,
+            new RMQNormalListner());
+        RMQNormalConsumer consumerSubTag1 = getConsumer(nsAddr, topic, sub3,
+            new RMQNormalListner());
+        RMQNormalConsumer consumerSubAll = getConsumer(nsAddr, topic, sub4,
+            new RMQNormalListner());
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        Collection<Object> msgsWithNoTag = producer.getMsgBodysCopy();
+
+        TagMessage tagMessage = new TagMessage(tags, topic, msgSize);
+        List<Object> tagMsgs = tagMessage.getMixedTagMessages();
+        producer.send(tagMsgs);
+        Assert.assertEquals("Not all are sent", msgSize * 3, producer.getAllUndupMsgBody().size());
+
+        consumerSubTwoMatchAll.getListner()
+            .waitForMessageConsume(tagMessage.getMessageBodyByTag(tags), consumeTime);
+        consumerSubTwoMachieOne.getListner()
+            .waitForMessageConsume(tagMessage.getMessageBodyByTag(tags[0]), consumeTime);
+        consumerSubTag1.getListner().waitForMessageConsume(tagMessage.getMessageBodyByTag(tags[0]),
+            consumeTime);
+        consumerSubAll.getListner().waitForMessageConsume(
+            MQMessageFactory.getMessage(msgsWithNoTag, tagMessage.getAllTagMessageBody()),
+            consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerSubTwoMatchAll.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getAllTagMessageBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerSubTwoMachieOne.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getMessageBodyByTag(tags[0]));
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerSubTag1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getMessageBodyByTag(tags[0]));
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumerSubAll.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(MQMessageFactory.getMessage(msgsWithNoTag,
+                tagMessage.getAllTagMessageBody()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java
new file mode 100644
index 0000000..03e81eb
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java
@@ -0,0 +1,115 @@
+/*
+ * 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.rocketmq.test.client.consumer.tag;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.RandomUtils;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class TagMessageWithSameGroupConsumerIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumerWithSameGroup() {
+        String tag = "jueyin";
+        int msgSize = 20;
+        String originMsgDCName = RandomUtils.getStringByUUID();
+        String msgBodyDCName = RandomUtils.getStringByUUID();
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, tag,
+            new RMQNormalListner(originMsgDCName, msgBodyDCName));
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), tag,
+            new RMQNormalListner(originMsgDCName, msgBodyDCName));
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testConsumerStartWithInterval() {
+        String tag = "jueyin";
+        int msgSize = 100;
+        String originMsgDCName = RandomUtils.getStringByUUID();
+        String msgBodyDCName = RandomUtils.getStringByUUID();
+
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, tag,
+            new RMQNormalListner(originMsgDCName, msgBodyDCName));
+        producer.send(tag, msgSize, 100);
+        TestUtils.waitForMonment(5);
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), tag,
+            new RMQNormalListner(originMsgDCName, msgBodyDCName));
+        TestUtils.waitForMonment(5);
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testConsumerStartTwoAndCrashOnsAfterWhile() {
+        String tag = "jueyin";
+        int msgSize = 100;
+        String originMsgDCName = RandomUtils.getStringByUUID();
+        String msgBodyDCName = RandomUtils.getStringByUUID();
+
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, tag,
+            new RMQNormalListner(originMsgDCName, msgBodyDCName));
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), tag,
+            new RMQNormalListner(originMsgDCName, msgBodyDCName));
+
+        producer.send(tag, msgSize, 100);
+        TestUtils.waitForMonment(5);
+        consumer2.shutdown();
+        mqClients.remove(1);
+        TestUtils.waitForMonment(5);
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/MulConsumerMulTopicIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/MulConsumerMulTopicIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/MulConsumerMulTopicIT.java
new file mode 100644
index 0000000..98d858b
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/MulConsumerMulTopicIT.java
@@ -0,0 +1,108 @@
+/*
+ * 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.rocketmq.test.client.consumer.topic;
+
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.MQWait;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class MulConsumerMulTopicIT extends BaseConf {
+    private RMQNormalProducer producer = null;
+
+    @Before
+    public void setUp() {
+        producer = getProducer(nsAddr, null);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSynSendMessage() {
+        int msgSize = 10;
+        String topic1 = initTopic();
+        String topic2 = initTopic();
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic1, "*", new RMQNormalListner());
+        consumer1.subscribe(topic2, "*");
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic1,
+            "*", new RMQNormalListner());
+        consumer2.subscribe(topic2, "*");
+
+        producer.send(MQMessageFactory.getMsg(topic1, msgSize));
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize));
+        Assert.assertEquals("Not all sent succeeded", msgSize * 2, producer.getAllUndupMsgBody().size());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+
+    @Test
+    public void testConsumeWithDiffTag() {
+        int msgSize = 10;
+        String topic1 = initTopic();
+        String topic2 = initTopic();
+        String tag = "jueyin_tag";
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic1, "*", new RMQNormalListner());
+        consumer1.subscribe(topic2, tag);
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic1,
+            "*", new RMQNormalListner());
+        consumer2.subscribe(topic2, tag);
+
+        producer.send(MQMessageFactory.getMsg(topic1, msgSize));
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize, tag));
+        Assert.assertEquals("Not all sent succeeded", msgSize * 2, producer.getAllUndupMsgBody().size());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+
+    @Test
+    public void testConsumeWithDiffTagAndFilter() {
+        int msgSize = 10;
+        String topic1 = initTopic();
+        String topic2 = initTopic();
+        String tag1 = "jueyin_tag_1";
+        String tag2 = "jueyin_tag_2";
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic1, "*", new RMQNormalListner());
+        consumer1.subscribe(topic2, tag1);
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, topic1, "*", new RMQNormalListner());
+        consumer2.subscribe(topic2, tag1);
+
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize, tag2));
+        producer.clearMsg();
+        producer.send(MQMessageFactory.getMsg(topic1, msgSize));
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize, tag1));
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/OneConsumerMulTopicIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/OneConsumerMulTopicIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/OneConsumerMulTopicIT.java
new file mode 100644
index 0000000..969fa79
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/topic/OneConsumerMulTopicIT.java
@@ -0,0 +1,104 @@
+/*
+ * 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.rocketmq.test.client.consumer.topic;
+
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OneConsumerMulTopicIT extends BaseConf {
+    private RMQNormalProducer producer = null;
+
+    @Before
+    public void setUp() {
+        producer = getProducer(nsAddr, null);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSynSendMessage() {
+        int msgSize = 10;
+        String topic1 = initTopic();
+        String topic2 = initTopic();
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic1, "*", new RMQNormalListner());
+        consumer.subscribe(topic2, "*");
+
+        producer.send(MQMessageFactory.getMsg(topic1, msgSize));
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize));
+
+        Assert.assertEquals("Not all are sent", msgSize * 2, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testConsumeWithDiffTag() {
+        int msgSize = 10;
+        String topic1 = initTopic();
+        String topic2 = initTopic();
+        String tag = "jueyin_tag";
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic1, "*", new RMQNormalListner());
+        consumer.subscribe(topic2, tag);
+
+        producer.send(MQMessageFactory.getMsg(topic1, msgSize));
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize, tag));
+
+        Assert.assertEquals("Not all are sent", msgSize * 2, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testConsumeWithDiffTagAndFilter() {
+        int msgSize = 10;
+        String topic1 = initTopic();
+        String topic2 = initTopic();
+        String tag1 = "jueyin_tag_1";
+        String tag2 = "jueyin_tag_2";
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic1, "*", new RMQNormalListner());
+        consumer.subscribe(topic2, tag1);
+
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize, tag2));
+        producer.clearMsg();
+        producer.send(MQMessageFactory.getMsg(topic1, msgSize));
+        producer.send(MQMessageFactory.getMsg(topic2, msgSize, tag1));
+
+        Assert.assertEquals("Not all are sent", msgSize * 2, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendExceptionIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendExceptionIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendExceptionIT.java
new file mode 100644
index 0000000..4125433
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendExceptionIT.java
@@ -0,0 +1,150 @@
+/*
+ * 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.rocketmq.test.client.producer.async;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.MessageQueueSelector;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.factory.ProducerFactory;
+import org.apache.rocketmq.test.factory.SendCallBackFactory;
+import org.apache.rocketmq.test.util.RandomUtils;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class AsyncSendExceptionIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private static boolean sendFail = false;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSendCallBackNull() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+        SendCallback sendCallback = null;
+        producer.send(msg, sendCallback);
+    }
+
+    @Test(expected = java.lang.NullPointerException.class)
+    public void testSendMQNull() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+        MessageQueue messageQueue = null;
+        producer.send(msg, messageQueue, SendCallBackFactory.getSendCallBack());
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSendSelectorNull() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+        MessageQueueSelector selector = null;
+        producer.send(msg, selector, 100, SendCallBackFactory.getSendCallBack());
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSelectorThrowsException() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+        producer.send(msg, new MessageQueueSelector() {
+            @Override
+            public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
+                String str = null;
+                return list.get(str.length());
+            }
+        }, null, SendCallBackFactory.getSendCallBack());
+    }
+
+    @Test
+    public void testQueueIdBigThanQueueNum() throws Exception {
+        int queueId = 100;
+        sendFail = false;
+        MessageQueue mq = new MessageQueue(topic, broker1Name, queueId);
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+
+        producer.send(msg, mq, new SendCallback() {
+            @Override
+            public void onSuccess(SendResult sendResult) {
+            }
+
+            @Override
+            public void onException(Throwable throwable) {
+                sendFail = true;
+            }
+        });
+
+        int checkNum = 50;
+        while (!sendFail && checkNum > 0) {
+            checkNum--;
+            TestUtils.waitForMonment(100);
+        }
+        producer.shutdown();
+        assertThat(sendFail).isEqualTo(true);
+    }
+
+    @Test
+    public void testQueueIdSmallZero() throws Exception {
+        int queueId = -100;
+        sendFail = true;
+        MessageQueue mq = new MessageQueue(topic, broker1Name, queueId);
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+
+        producer.send(msg, mq, new SendCallback() {
+            @Override
+            public void onSuccess(SendResult sendResult) {
+                sendFail = false;
+            }
+
+            @Override
+            public void onException(Throwable throwable) {
+                sendFail = true;
+            }
+        });
+
+        int checkNum = 50;
+        while (sendFail && checkNum > 0) {
+            checkNum--;
+            TestUtils.waitForMonment(100);
+        }
+        producer.shutdown();
+        assertThat(sendFail).isEqualTo(false);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java
new file mode 100644
index 0000000..53a992c
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java
@@ -0,0 +1,85 @@
+/*
+ * 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.rocketmq.test.client.producer.async;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class AsyncSendWithMessageQueueIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private static boolean sendFail = false;
+    private RMQAsyncSendProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+        producer = getAsyncProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testAsyncSendWithMQ() {
+        int msgSize = 20;
+        int queueId = 0;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        MessageQueue mq = new MessageQueue(topic, broker1Name, queueId);
+
+        producer.asyncSend(msgSize, mq);
+        producer.waitForResponse(5 * 1000);
+        assertThat(producer.getSuccessMsgCount()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        VerifyUtils.verifyMessageQueueId(queueId, consumer.getListner().getAllOriginMsg());
+
+        producer.clearMsg();
+        consumer.clearMsg();
+
+        mq = new MessageQueue(topic, broker2Name, queueId);
+        producer.asyncSend(msgSize, mq);
+        producer.waitForResponse(5 * 1000);
+        assertThat(producer.getSuccessMsgCount()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        VerifyUtils.verifyMessageQueueId(queueId, consumer.getListner().getAllOriginMsg());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
new file mode 100644
index 0000000..68c2b0e
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
@@ -0,0 +1,106 @@
+/*
+ * 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.rocketmq.test.client.producer.async;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.producer.MessageQueueSelector;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class AsyncSendWithMessageQueueSelectorIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private static boolean sendFail = false;
+    private RMQAsyncSendProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+        producer = getAsyncProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSendWithSelector() {
+        int msgSize = 20;
+        final int queueId = 0;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        producer.asyncSend(msgSize, new MessageQueueSelector() {
+            @Override
+            public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
+                for (MessageQueue mq : list) {
+                    if (mq.getQueueId() == queueId && mq.getBrokerName().equals(broker1Name)) {
+                        return mq;
+                    }
+                }
+                return list.get(0);
+            }
+        });
+        producer.waitForResponse(5 * 1000);
+        assertThat(producer.getSuccessMsgCount()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        VerifyUtils.verifyMessageQueueId(queueId, consumer.getListner().getAllOriginMsg());
+
+        producer.clearMsg();
+        consumer.clearMsg();
+
+        producer.asyncSend(msgSize, new MessageQueueSelector() {
+            @Override
+            public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
+                for (MessageQueue mq : list) {
+                    if (mq.getQueueId() == queueId && mq.getBrokerName().equals(broker2Name)) {
+                        return mq;
+                    }
+                }
+                return list.get(8);
+            }
+        });
+        producer.waitForResponse(5 * 1000);
+        assertThat(producer.getSuccessMsgCount()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        VerifyUtils.verifyMessageQueueId(queueId, consumer.getListner().getAllOriginMsg());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithOnlySendCallBackIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithOnlySendCallBackIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithOnlySendCallBackIT.java
new file mode 100644
index 0000000..51aeef4
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithOnlySendCallBackIT.java
@@ -0,0 +1,64 @@
+/*
+ * 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.rocketmq.test.client.producer.async;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class AsyncSendWithOnlySendCallBackIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private RMQAsyncSendProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+        producer = getAsyncProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSendWithOnlyCallBack() {
+        int msgSize = 20;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        producer.asyncSend(msgSize);
+        producer.waitForResponse(10 * 1000);
+        assertThat(producer.getSuccessMsgCount()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/ChinaPropIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/ChinaPropIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/ChinaPropIT.java
new file mode 100644
index 0000000..e524fb3
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/ChinaPropIT.java
@@ -0,0 +1,74 @@
+/*
+ * 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.rocketmq.test.client.producer.exception.msg;
+
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.factory.MessageFactory;
+import org.apache.rocketmq.test.factory.ProducerFactory;
+import org.apache.rocketmq.test.util.RandomUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class ChinaPropIT extends BaseConf {
+    private static DefaultMQProducer producer = null;
+    private static String topic = null;
+
+    @Before
+    public void setUp() {
+        producer = ProducerFactory.getRMQProducer(nsAddr);
+        topic = initTopic();
+    }
+
+    @After
+    public void tearDown() {
+        producer.shutdown();
+    }
+
+    /**
+     * @since version3.4.6
+     */
+    @Test(expected = org.apache.rocketmq.client.exception.MQBrokerException.class)
+    public void testSend20kChinaPropMsg() throws Exception {
+        Message msg = MessageFactory.getRandomMessage(topic);
+        msg.putUserProperty("key", RandomUtils.getCheseWord(32 * 1024 + 1));
+        producer.send(msg);
+    }
+
+    /**
+     * @since version3.4.6
+     */
+    @Test
+    public void testSend10kChinaPropMsg() {
+
+        Message msg = MessageFactory.getRandomMessage(topic);
+        msg.putUserProperty("key", RandomUtils.getCheseWord(10 * 1024));
+        SendResult sendResult = null;
+        try {
+            sendResult = producer.send(msg);
+        } catch (Exception e) {
+        }
+        assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageExceptionIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageExceptionIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageExceptionIT.java
new file mode 100644
index 0000000..6fa8bd9
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageExceptionIT.java
@@ -0,0 +1,129 @@
+/*
+ * 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.rocketmq.test.client.producer.exception.msg;
+
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.factory.MessageFactory;
+import org.apache.rocketmq.test.factory.ProducerFactory;
+import org.apache.rocketmq.test.util.RandomUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class MessageExceptionIT extends BaseConf {
+    private static DefaultMQProducer producer = null;
+    private static String topic = null;
+
+    @Before
+    public void setUp() {
+        producer = ProducerFactory.getRMQProducer(nsAddr);
+        topic = initTopic();
+    }
+
+    @After
+    public void tearDown() {
+        producer.shutdown();
+    }
+
+    @Test
+    public void testProducerSmoke() {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        SendResult sendResult = null;
+        try {
+            sendResult = producer.send(msg);
+        } catch (Exception e) {
+        }
+
+        assertThat(sendResult).isNotEqualTo(null);
+        assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSynSendNullMessage() throws Exception {
+        producer.send(null);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSynSendNullBodyMessage() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        msg.setBody(null);
+        producer.send(msg);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSynSendZeroSizeBodyMessage() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        msg.setBody(new byte[0]);
+        producer.send(msg);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSynSendOutOfSizeBodyMessage() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        msg.setBody(new byte[1024 * 1024 * 4 + 1]);
+        producer.send(msg);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSynSendNullTopicMessage() throws Exception {
+        Message msg = new Message(null, RandomUtils.getStringByUUID().getBytes());
+        producer.send(msg);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSynSendBlankTopicMessage() throws Exception {
+        Message msg = new Message("", RandomUtils.getStringByUUID().getBytes());
+        producer.send(msg);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSend128kMsg() throws Exception {
+        Message msg = new Message(topic,
+            RandomUtils.getStringWithNumber(1024 * 1024 * 4 + 1).getBytes());
+        producer.send(msg);
+    }
+
+    @Test
+    public void testSendLess128kMsg() {
+        Message msg = new Message(topic, RandomUtils.getStringWithNumber(128 * 1024).getBytes());
+        SendResult sendResult = null;
+        try {
+            sendResult = producer.send(msg);
+        } catch (Exception e) {
+        }
+        assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK);
+    }
+
+    @Test
+    public void testSendMsgWithUserProperty() {
+        Message msg = MessageFactory.getRandomMessage(topic);
+        msg.putUserProperty("key", RandomUtils.getCheseWord(10 * 1024));
+        SendResult sendResult = null;
+        try {
+            sendResult = producer.send(msg);
+        } catch (Exception e) {
+        }
+        assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageUserPropIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageUserPropIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageUserPropIT.java
new file mode 100644
index 0000000..b5882df
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/msg/MessageUserPropIT.java
@@ -0,0 +1,94 @@
+/*
+ * 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.rocketmq.test.client.producer.exception.msg;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.balance.NormalMsgStaticBalanceIT;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MessageFactory;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class MessageUserPropIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    /**
+     * @since version3.4.6
+     */
+    @Test
+    public void testSendEnglishUserProp() {
+        Message msg = MessageFactory.getRandomMessage(topic);
+        String msgKey = "jueyinKey";
+        String msgValue = "jueyinValue";
+        msg.putUserProperty(msgKey, msgValue);
+
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        producer.send(msg, null);
+        assertThat(producer.getAllMsgBody().size()).isEqualTo(1);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        Message sendMsg = (Message) producer.getFirstMsg();
+        Message recvMsg = (Message) consumer.getListner().getFirstMsg();
+        assertThat(recvMsg.getUserProperty(msgKey)).isEqualTo(sendMsg.getUserProperty(msgKey));
+    }
+
+    /**
+     * @since version3.4.6
+     */
+    @Test
+    public void testSendChinaUserProp() {
+        Message msg = MessageFactory.getRandomMessage(topic);
+        String msgKey = "jueyinKey";
+        String msgValue = "jueyinzhi";
+        msg.putUserProperty(msgKey, msgValue);
+
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        producer.send(msg, null);
+        assertThat(producer.getAllMsgBody().size()).isEqualTo(1);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        Message sendMsg = (Message) producer.getFirstMsg();
+        Message recvMsg = (Message) consumer.getListner().getFirstMsg();
+        assertThat(recvMsg.getUserProperty(msgKey)).isEqualTo(sendMsg.getUserProperty(msgKey));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/producer/ProducerGroupAndInstanceNameValidityIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/producer/ProducerGroupAndInstanceNameValidityIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/producer/ProducerGroupAndInstanceNameValidityIT.java
new file mode 100644
index 0000000..fbaa3c2
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/exception/producer/ProducerGroupAndInstanceNameValidityIT.java
@@ -0,0 +1,69 @@
+/*
+ * 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.rocketmq.test.client.producer.exception.producer;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.util.RandomUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class ProducerGroupAndInstanceNameValidityIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(ProducerGroupAndInstanceNameValidityIT.class);
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    /**
+     * @since version3.4.6
+     */
+    @Test
+    public void testTwoProducerSameGroupAndInstanceName() {
+        RMQNormalProducer producer1 = getProducer(nsAddr, topic);
+        assertThat(producer1.isStartSuccess()).isEqualTo(true);
+        RMQNormalProducer producer2 = getProducer(nsAddr, topic,
+            producer1.getProducerGroupName(), producer1.getProducerInstanceName());
+        assertThat(producer2.isStartSuccess()).isEqualTo(false);
+    }
+
+    /**
+     * @since version3.4.6
+     */
+    @Test
+    public void testTwoProducerSameGroup() {
+        RMQNormalProducer producer1 = getProducer(nsAddr, topic);
+        assertThat(producer1.isStartSuccess()).isEqualTo(true);
+        RMQNormalProducer producer2 = getProducer(nsAddr, topic,
+            producer1.getProducerGroupName(), RandomUtils.getStringByUUID());
+        assertThat(producer2.isStartSuccess()).isEqualTo(true);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendExceptionIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendExceptionIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendExceptionIT.java
new file mode 100644
index 0000000..19d8ca5
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendExceptionIT.java
@@ -0,0 +1,78 @@
+/*
+ * 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.rocketmq.test.client.producer.oneway;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.MessageQueueSelector;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.factory.ProducerFactory;
+import org.apache.rocketmq.test.util.RandomUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class OneWaySendExceptionIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private static boolean sendFail = false;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test(expected = java.lang.NullPointerException.class)
+    public void testSendMQNull() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+        MessageQueue messageQueue = null;
+        producer.sendOneway(msg, messageQueue);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSendSelectorNull() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+        MessageQueueSelector selector = null;
+        producer.sendOneway(msg, selector, 100);
+    }
+
+    @Test(expected = org.apache.rocketmq.client.exception.MQClientException.class)
+    public void testSelectorThrowsException() throws Exception {
+        Message msg = new Message(topic, RandomUtils.getStringByUUID().getBytes());
+        DefaultMQProducer producer = ProducerFactory.getRMQProducer(nsAddr);
+        producer.sendOneway(msg, new MessageQueueSelector() {
+            @Override
+            public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
+                String str = null;
+                return list.get(str.length());
+            }
+        }, null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendIT.java
new file mode 100644
index 0000000..37df4f8
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendIT.java
@@ -0,0 +1,64 @@
+/*
+ * 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.rocketmq.test.client.producer.oneway;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OneWaySendIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private RMQAsyncSendProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+        producer = getAsyncProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testOneWaySendWithOnlyMsgAsParam() {
+        int msgSize = 20;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        producer.sendOneWay(msgSize);
+        producer.waitForResponse(5 * 1000);
+        assertThat(producer.getAllMsgBody().size()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithMQIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithMQIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithMQIT.java
new file mode 100644
index 0000000..a2b601b
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithMQIT.java
@@ -0,0 +1,79 @@
+/*
+ * 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.rocketmq.test.client.producer.oneway;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OneWaySendWithMQIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private static boolean sendFail = false;
+    private RMQAsyncSendProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+        producer = getAsyncProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testAsyncSendWithMQ() {
+        int msgSize = 20;
+        int queueId = 0;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        MessageQueue mq = new MessageQueue(topic, broker1Name, queueId);
+
+        producer.sendOneWay(msgSize, mq);
+        producer.waitForResponse(5 * 1000);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        producer.clearMsg();
+        consumer.clearMsg();
+
+        mq = new MessageQueue(topic, broker2Name, queueId);
+        producer.asyncSend(msgSize, mq);
+        producer.waitForResponse(5 * 1000);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithSelectorIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithSelectorIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithSelectorIT.java
new file mode 100644
index 0000000..aa70556
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/oneway/OneWaySendWithSelectorIT.java
@@ -0,0 +1,104 @@
+/*
+ * 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.rocketmq.test.client.producer.oneway;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.producer.MessageQueueSelector;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.tag.TagMessageWith1ConsumerIT;
+import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OneWaySendWithSelectorIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private static boolean sendFail = false;
+    private RMQAsyncSendProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("user topic[%s]!", topic));
+        producer = getAsyncProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSendWithSelector() {
+        int msgSize = 20;
+        final int queueId = 0;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        producer.sendOneWay(msgSize, new MessageQueueSelector() {
+            @Override
+            public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
+                for (MessageQueue mq : list) {
+                    if (mq.getQueueId() == queueId && mq.getBrokerName().equals(broker1Name)) {
+                        return mq;
+                    }
+                }
+                return list.get(0);
+            }
+        });
+        assertThat(producer.getAllMsgBody().size()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        VerifyUtils.verifyMessageQueueId(queueId, consumer.getListner().getAllOriginMsg());
+
+        producer.clearMsg();
+        consumer.clearMsg();
+
+        producer.sendOneWay(msgSize, new MessageQueueSelector() {
+            @Override
+            public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
+                for (MessageQueue mq : list) {
+                    if (mq.getQueueId() == queueId && mq.getBrokerName().equals(broker2Name)) {
+                        return mq;
+                    }
+                }
+                return list.get(8);
+            }
+        });
+        assertThat(producer.getAllMsgBody().size()).isEqualTo(msgSize);
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        VerifyUtils.verifyMessageQueueId(queueId, consumer.getListner().getAllOriginMsg());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgDynamicRebalanceIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgDynamicRebalanceIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgDynamicRebalanceIT.java
new file mode 100644
index 0000000..a6520b4
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgDynamicRebalanceIT.java
@@ -0,0 +1,115 @@
+/*
+ * 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.rocketmq.test.client.producer.order;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.balance.NormalMsgStaticBalanceIT;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.order.RMQOrderListener;
+import org.apache.rocketmq.test.message.MessageQueueMsg;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OrderMsgDynamicRebalanceIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumerAndCrashOne() {
+        int msgSize = 10;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*",
+            new RMQOrderListener("1"));
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQOrderListener("2"));
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        MQWait.waitConsumeAll(30 * 1000, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner());
+        consumer2.shutdown();
+
+        mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer1.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer2.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testThreeConsumerAndCrashOne() {
+        int msgSize = 10;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*",
+            new RMQOrderListener("1"));
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQOrderListener("2"));
+        RMQNormalConsumer consumer3 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQOrderListener("3"));
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner(), consumer3.getListner());
+        consumer3.shutdown();
+
+        mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        boolean recvAll = MQWait.waitConsumeAll(30 * 1000, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner(), consumer3.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer1.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer2.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer3.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgIT.java
new file mode 100644
index 0000000..006aaa1
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgIT.java
@@ -0,0 +1,108 @@
+/*
+ * 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.rocketmq.test.client.producer.order;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.listener.rmq.order.RMQOrderListener;
+import org.apache.rocketmq.test.message.MessageQueueMsg;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OrderMsgIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(OrderMsgIT.class);
+    private RMQNormalProducer producer = null;
+    private RMQNormalConsumer consumer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+        consumer = getConsumer(nsAddr, topic, "*", new RMQOrderListener());
+    }
+
+    @After
+    public void tearDown() {
+        shutDown();
+    }
+
+    @Test
+    public void testOrderMsg() {
+        int msgSize = 10;
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(mqMsgs.getMsgBodys());
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testSendOneQueue() {
+        int msgSize = 20;
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(MQMessageFactory.getMessageQueues(mqs.get(0)),
+            msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(mqMsgs.getMsgBodys());
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testSendRandomQueues() {
+        int msgSize = 10;
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(
+            MQMessageFactory.getMessageQueues(mqs.get(0), mqs.get(1), mqs.get(mqs.size() - 1)),
+            msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(mqMsgs.getMsgBodys());
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+}


[05/13] incubator-rocketmq git commit: [RocketMQ-58] Add integration test for RocketMQ, also thanks @fenglianghfl for this commit, closes apache/incubator-rocketmq#46

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgRebalanceIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgRebalanceIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgRebalanceIT.java
new file mode 100644
index 0000000..57b69d2
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgRebalanceIT.java
@@ -0,0 +1,133 @@
+/*
+ * 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.rocketmq.test.client.producer.order;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.order.RMQOrderListener;
+import org.apache.rocketmq.test.message.MessageQueueMsg;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OrderMsgRebalanceIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(OrderMsgRebalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumersBalance() {
+        int msgSize = 10;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQOrderListener());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQOrderListener());
+        TestUtils.waitForSeconds(waitTime);
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        boolean balance = VerifyUtils.verifyBalance(producer.getAllMsgBody().size(),
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer1.getListner().getAllUndupMsgBody()).size(),
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer2.getListner().getAllUndupMsgBody()).size());
+        assertThat(balance).isEqualTo(true);
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer1.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer2.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testFourConsuemrBalance() {
+        int msgSize = 20;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQOrderListener());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQOrderListener());
+        RMQNormalConsumer consumer3 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQOrderListener());
+        RMQNormalConsumer consumer4 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQOrderListener());
+        TestUtils.waitForSeconds(waitTime);
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner(), consumer3.getListner(),
+            consumer4.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        boolean balance = VerifyUtils
+            .verifyBalance(producer.getAllMsgBody().size(),
+                VerifyUtils
+                    .getFilterdMessage(producer.getAllMsgBody(),
+                        consumer1.getListner().getAllUndupMsgBody())
+                    .size(),
+                VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                    consumer2.getListner().getAllUndupMsgBody()).size(),
+                VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                    consumer3.getListner().getAllUndupMsgBody()).size(),
+                VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                    consumer4.getListner().getAllUndupMsgBody()).size());
+        logger.info(String.format("consumer1:%s;consumer2:%s;consumer3:%s,consumer4:%s",
+            consumer1.getListner().getAllMsgBody().size(),
+            consumer2.getListner().getAllMsgBody().size(),
+            consumer3.getListner().getAllMsgBody().size(),
+            consumer4.getListner().getAllMsgBody().size()));
+        assertThat(balance).isEqualTo(true);
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer1.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer2.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer3.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer4.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgWithTagIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgWithTagIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgWithTagIT.java
new file mode 100644
index 0000000..7db77de
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/order/OrderMsgWithTagIT.java
@@ -0,0 +1,169 @@
+/*
+ * 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.rocketmq.test.client.producer.order;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.order.RMQOrderListener;
+import org.apache.rocketmq.test.message.MessageQueueMsg;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OrderMsgWithTagIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(OrderMsgIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        shutDown();
+    }
+
+    @Test
+    public void testOrderMsgWithTagSubAll() {
+        int msgSize = 10;
+        String tag = "jueyin_tag";
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQOrderListener());
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize, tag);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(mqMsgs.getMsgBodys());
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testOrderMsgWithTagSubTag() {
+        int msgSize = 5;
+        String tag = "jueyin_tag";
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, tag, new RMQOrderListener());
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize, tag);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(mqMsgs.getMsgBodys());
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testOrderMsgWithTag1AndTag2SubTag1() {
+        int msgSize = 5;
+        String tag1 = "jueyin_tag_1";
+        String tag2 = "jueyin_tag_2";
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, tag1, new RMQOrderListener());
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize, tag2);
+        producer.send(mqMsgs.getMsgsWithMQ());
+        producer.clearMsg();
+
+        mqMsgs = new MessageQueueMsg(mqs, msgSize, tag1);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(mqMsgs.getMsgBodys());
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testTwoConsumerSubTag() {
+        int msgSize = 10;
+        String tag1 = "jueyin_tag_1";
+        String tag2 = "jueyin_tag_2";
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, tag1,
+            new RMQOrderListener("consumer1"));
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, topic, tag2,
+            new RMQOrderListener("consumer2"));
+        List<MessageQueue> mqs = producer.getMessageQueue();
+
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize, tag1);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        mqMsgs = new MessageQueueMsg(mqs, msgSize, tag2);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer1.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer2.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+
+    @Test
+    public void testConsumeTwoTag() {
+        int msgSize = 10;
+        String tag1 = "jueyin_tag_1";
+        String tag2 = "jueyin_tag_2";
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic,
+            String.format("%s||%s", tag1, tag2), new RMQOrderListener());
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize, tag1);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        mqMsgs = new MessageQueueMsg(mqs, msgSize, tag2);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdExceptionIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdExceptionIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdExceptionIT.java
new file mode 100644
index 0000000..a1520a0
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdExceptionIT.java
@@ -0,0 +1,81 @@
+/*
+ * 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.rocketmq.test.client.producer.querymsg;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class QueryMsgByIdExceptionIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(QueryMsgByKeyIT.class);
+    private static RMQNormalProducer producer = null;
+    private static String topic = null;
+
+    @BeforeClass
+    public static void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @AfterClass
+    public static void tearDown() {
+        shutDown();
+    }
+
+    @Test
+    public void testQueryMsgByErrorMsgId() {
+        producer.clearMsg();
+        int msgSize = 20;
+        String errorMsgId = "errorMsgId";
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        MessageExt queryMsg = null;
+        try {
+            queryMsg = producer.getProducer().viewMessage(errorMsgId);
+        } catch (Exception e) {
+        }
+
+        assertThat(queryMsg).isNull();
+    }
+
+    @Test
+    public void testQueryMsgByNullMsgId() {
+        producer.clearMsg();
+        int msgSize = 20;
+        String errorMsgId = null;
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        MessageExt queryMsg = null;
+        try {
+            queryMsg = producer.getProducer().viewMessage(errorMsgId);
+        } catch (Exception e) {
+        }
+
+        assertThat(queryMsg).isNull();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdIT.java
new file mode 100644
index 0000000..92c40c7
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByIdIT.java
@@ -0,0 +1,75 @@
+/*
+ * 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.rocketmq.test.client.producer.querymsg;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageClientExt;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class QueryMsgByIdIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(QueryMsgByIdIT.class);
+    private RMQNormalProducer producer = null;
+    private RMQNormalConsumer consumer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+        consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+    }
+
+    @After
+    public void tearDown() {
+        shutDown();
+    }
+
+    @Test
+    public void testQueryMsg() {
+        int msgSize = 20;
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        Assert.assertEquals("Not all are consumed", 0, VerifyUtils.verify(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()));
+
+        MessageExt recvMsg = (MessageExt) consumer.getListner().getFirstMsg();
+        MessageExt queryMsg = null;
+        try {
+            TestUtils.waitForMonment(3000);
+            queryMsg = producer.getProducer().viewMessage(((MessageClientExt) recvMsg).getOffsetMsgId());
+        } catch (Exception e) {
+        }
+
+        assertThat(queryMsg).isNotNull();
+        assertThat(new String(queryMsg.getBody())).isEqualTo(new String(recvMsg.getBody()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByKeyIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByKeyIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByKeyIT.java
new file mode 100644
index 0000000..ec45a29
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/querymsg/QueryMsgByKeyIT.java
@@ -0,0 +1,104 @@
+/*
+ * 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.rocketmq.test.client.producer.querymsg;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class QueryMsgByKeyIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(QueryMsgByKeyIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        shutDown();
+    }
+
+    @Test
+    public void testQueryMsg() {
+        int msgSize = 20;
+        String key = "jueyin";
+        long begin = System.currentTimeMillis();
+        List<Object> msgs = MQMessageFactory.getKeyMsg(topic, key, msgSize);
+        producer.send(msgs);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        List<MessageExt> queryMsgs = null;
+        try {
+            TestUtils.waitForMonment(500 * 3);
+            queryMsgs = producer.getProducer().queryMessage(topic, key, msgSize, begin - 5000,
+                System.currentTimeMillis() + 5000).getMessageList();
+        } catch (Exception e) {
+        }
+
+        assertThat(queryMsgs).isNotNull();
+        assertThat(queryMsgs.size()).isEqualTo(msgSize);
+    }
+
+    @Test
+    public void testQueryMax() {
+        int msgSize = 500;
+        int max = 64 * brokerNum;
+        String key = "jueyin";
+        long begin = System.currentTimeMillis();
+        List<Object> msgs = MQMessageFactory.getKeyMsg(topic, key, msgSize);
+        producer.send(msgs);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        List<MessageExt> queryMsgs = null;
+        try {
+            queryMsgs = producer.getProducer().queryMessage(topic, key, msgSize, begin - 15000,
+                System.currentTimeMillis() + 15000).getMessageList();
+
+            int i = 3;
+            while (queryMsgs == null || queryMsgs.size() != brokerNum) {
+                i--;
+                queryMsgs = producer.getProducer().queryMessage(topic, key, msgSize, begin - 15000,
+                    System.currentTimeMillis() + 15000).getMessageList();
+                TestUtils.waitForMonment(1000);
+
+                if (i == 0 || (queryMsgs != null && queryMsgs.size() == max)) {
+                    break;
+                }
+            }
+        } catch (Exception e) {
+        }
+
+        assertThat(queryMsgs).isNotNull();
+        assertThat(queryMsgs.size()).isEqualTo(max);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/delay/DelayConf.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/delay/DelayConf.java b/test/src/test/java/org/apache/rocketmq/test/delay/DelayConf.java
new file mode 100644
index 0000000..6c23473
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/delay/DelayConf.java
@@ -0,0 +1,27 @@
+/*
+ * 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.rocketmq.test.delay;
+
+import org.apache.rocketmq.test.base.BaseConf;
+
+public class DelayConf extends BaseConf {
+    protected static final int[] DELAY_LEVEL = {
+        1, 5, 10, 30, 1 * 60, 5 * 60, 10 * 60,
+        30 * 60, 1 * 3600, 2 * 3600, 6 * 3600, 12 * 3600, 1 * 24 * 3600};
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java b/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java
new file mode 100644
index 0000000..5206dcb
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java
@@ -0,0 +1,116 @@
+/*
+ * 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.rocketmq.test.delay;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.balance.NormalMsgStaticBalanceIT;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQDelayListner;
+import org.apache.rocketmq.test.listener.rmq.order.RMQOrderListener;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NormalMsgDelayIT extends DelayConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    protected int msgSize = 100;
+    private RMQNormalProducer producer = null;
+    private RMQNormalConsumer consumer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+        consumer = getConsumer(nsAddr, topic, "*", new RMQOrderListener());
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testDelayLevell() {
+        int delayLevel = 1;
+        List<Object> delayMsgs = MQMessageFactory.getDelayMsg(topic, delayLevel, msgSize);
+        producer.send(delayMsgs);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        Assert.assertEquals("Not all are consumed", 0, VerifyUtils.verify(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()));
+        Assert.assertEquals("Timer is not correct", true,
+            VerifyUtils.verifyDelay(DELAY_LEVEL[delayLevel - 1] * 1000,
+                ((RMQDelayListner) consumer.getListner()).getMsgDelayTimes()));
+    }
+
+    @Test
+    public void testDelayLevel2() {
+        int delayLevel = 2;
+        List<Object> delayMsgs = MQMessageFactory.getDelayMsg(topic, delayLevel, msgSize);
+        producer.send(delayMsgs);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(),
+            DELAY_LEVEL[delayLevel - 1] * 1000 * 2);
+        Assert.assertEquals("Not all are consumed", 0, VerifyUtils.verify(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()));
+        Assert.assertEquals("Timer is not correct", true,
+            VerifyUtils.verifyDelay(DELAY_LEVEL[delayLevel - 1] * 1000,
+                ((RMQDelayListner) consumer.getListner()).getMsgDelayTimes()));
+    }
+
+    @Test
+    public void testDelayLevel3() {
+        int delayLevel = 3;
+        List<Object> delayMsgs = MQMessageFactory.getDelayMsg(topic, delayLevel, msgSize);
+        producer.send(delayMsgs);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(),
+            DELAY_LEVEL[delayLevel - 1] * 1000 * 2);
+        Assert.assertEquals("Not all are consumed", 0, VerifyUtils.verify(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()));
+        Assert.assertEquals("Timer is not correct", true,
+            VerifyUtils.verifyDelay(DELAY_LEVEL[delayLevel - 1] * 1000,
+                ((RMQDelayListner) consumer.getListner()).getMsgDelayTimes()));
+    }
+
+    @Test
+    public void testDelayLevel4() {
+        int delayLevel = 4;
+        List<Object> delayMsgs = MQMessageFactory.getDelayMsg(topic, delayLevel, msgSize);
+        producer.send(delayMsgs);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(),
+            DELAY_LEVEL[delayLevel - 1] * 1000 * 2);
+        Assert.assertEquals("Not all are consumed", 0, VerifyUtils.verify(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()));
+        Assert.assertEquals("Timer is not correct", true,
+            VerifyUtils.verifyDelay(DELAY_LEVEL[delayLevel - 1] * 1000,
+                ((RMQDelayListner) consumer.getListner()).getMsgDelayTimes()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/smoke/NormalMessageSendAndRecvIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/smoke/NormalMessageSendAndRecvIT.java b/test/src/test/java/org/apache/rocketmq/test/smoke/NormalMessageSendAndRecvIT.java
new file mode 100644
index 0000000..c422501
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/smoke/NormalMessageSendAndRecvIT.java
@@ -0,0 +1,62 @@
+/*
+ * 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.rocketmq.test.smoke;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class NormalMessageSendAndRecvIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMessageSendAndRecvIT.class);
+    private RMQNormalConsumer consumer = null;
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+        consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSynSendMessage() {
+        int msgSize = 10;
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/resources/log4j.xml
----------------------------------------------------------------------
diff --git a/test/src/test/resources/log4j.xml b/test/src/test/resources/log4j.xml
new file mode 100644
index 0000000..3031095
--- /dev/null
+++ b/test/src/test/resources/log4j.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%d %p [%F %M %L]: %m%n"/>
+        </layout>
+        <filter class="org.apache.log4j.varia.LevelRangeFilter">
+            <param name="LevelMax" value="ERROR"/>
+            <param name="LevelMin" value="TRACE"/>
+        </filter>
+    </appender>
+
+    <appender name="TOTAL" class="org.apache.log4j.RollingFileAppender">
+        <param name="File" value="it_test.log"/>
+        <param name="append" value="false"/>
+        <param name="MaxFileSize" value="10240000"/>
+        <param name="MaxBackupIndex" value="10"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%d - %c -%-4r [%t] %-5p %x - %m%n"/>
+        </layout>
+    </appender>
+
+    <root>
+        <level value="OFF"/>
+        <appender-ref ref="TOTAL"/>
+    </root>
+</log4j:configuration>

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/test/src/test/resources/logback-test.xml b/test/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..eb12a9a
--- /dev/null
+++ b/test/src/test/resources/logback-test.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<configuration>
+
+    <appender name="DefaultAppender" class="ch.qos.logback.core.ConsoleAppender">
+        <append>true</append>
+        <encoder>
+            <pattern>%d{yyy-MM-dd HH\:mm\:ss,GMT+8} %p %t - %m%n</pattern>
+            <charset class="java.nio.charset.Charset">UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <root>
+        <level value="OFF"/>
+        <appender-ref ref="DefaultAppender"/>
+    </root>
+</configuration>



[07/13] incubator-rocketmq git commit: [RocketMQ-58] Add integration test for RocketMQ, also thanks @fenglianghfl for this commit, closes apache/incubator-rocketmq#46

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgDynamicBalanceIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgDynamicBalanceIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgDynamicBalanceIT.java
new file mode 100644
index 0000000..fdafdf0
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgDynamicBalanceIT.java
@@ -0,0 +1,111 @@
+/*
+ * 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.rocketmq.test.client.consumer.balance;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class NormalMsgDynamicBalanceIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumerAndCrashOne() {
+        int msgSize = 400;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+
+        producer.send(msgSize);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner());
+        consumer2.shutdown();
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize * 2, producer.getAllUndupMsgBody().size());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        boolean balance = VerifyUtils.verifyBalance(msgSize,
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer1.getListner().getAllUndupMsgBody()).size() - msgSize,
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer2.getListner().getAllUndupMsgBody()).size());
+        assertThat(balance).isEqualTo(true);
+    }
+
+    @Test
+    public void test3ConsumerAndCrashOne() {
+        int msgSize = 400;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        RMQNormalConsumer consumer3 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+
+        producer.send(msgSize);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner(), consumer3.getListner());
+        consumer3.shutdown();
+        producer.clearMsg();
+        consumer1.clearMsg();
+        consumer2.clearMsg();
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        boolean balance = VerifyUtils.verifyBalance(msgSize,
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer1.getListner().getAllUndupMsgBody()).size(),
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer2.getListner().getAllUndupMsgBody()).size());
+        assertThat(balance).isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgStaticBalanceIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgStaticBalanceIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgStaticBalanceIT.java
new file mode 100644
index 0000000..117d643
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/balance/NormalMsgStaticBalanceIT.java
@@ -0,0 +1,109 @@
+/*
+ * 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.rocketmq.test.client.consumer.balance;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class NormalMsgStaticBalanceIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumersBalance() {
+        int msgSize = 400;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        boolean balance = VerifyUtils.verifyBalance(msgSize,
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer1.getListner().getAllUndupMsgBody()).size(),
+            VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                consumer2.getListner().getAllUndupMsgBody()).size());
+        assertThat(balance).isEqualTo(true);
+    }
+
+    @Test
+    public void testFourConsumersBalance() {
+        int msgSize = 600;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        RMQNormalConsumer consumer3 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        RMQNormalConsumer consumer4 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner(), consumer3.getListner(),
+            consumer4.getListner());
+        assertThat(recvAll).isEqualTo(true);
+
+        boolean balance = VerifyUtils
+            .verifyBalance(msgSize,
+                VerifyUtils
+                    .getFilterdMessage(producer.getAllMsgBody(),
+                        consumer1.getListner().getAllUndupMsgBody())
+                    .size(),
+                VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                    consumer2.getListner().getAllUndupMsgBody()).size(),
+                VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                    consumer3.getListner().getAllUndupMsgBody()).size(),
+                VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+                    consumer4.getListner().getAllUndupMsgBody()).size());
+        assertThat(balance).isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/BaseBroadCastIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/BaseBroadCastIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/BaseBroadCastIT.java
new file mode 100644
index 0000000..94efaef
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/BaseBroadCastIT.java
@@ -0,0 +1,56 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.factory.ConsumerFactory;
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+public class BaseBroadCastIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(BaseBroadCastIT.class);
+
+    public static RMQBroadCastConsumer getBroadCastConsumer(String nsAddr, String topic,
+        String subExpression,
+        AbstractListener listner) {
+        String consumerGroup = initConsumerGroup();
+        return getBroadCastConsumer(nsAddr, consumerGroup, topic, subExpression, listner);
+    }
+
+    public static RMQBroadCastConsumer getBroadCastConsumer(String nsAddr, String consumerGroup,
+        String topic, String subExpression,
+        AbstractListener listner) {
+        RMQBroadCastConsumer consumer = ConsumerFactory.getRMQBroadCastConsumer(nsAddr,
+            consumerGroup, topic, subExpression, listner);
+
+        consumer.setDebug();
+
+        mqClients.add(consumer);
+        logger.info(String.format("consumer[%s] start,topic[%s],subExpression[%s]", consumerGroup,
+            topic, subExpression));
+        return consumer;
+    }
+
+    public void printSeperator() {
+        for (int i = 0; i < 3; i++) {
+            logger.info(
+                "<<<<<<<<================================================================================>>>>>>>>");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java
new file mode 100644
index 0000000..65762fa
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java
@@ -0,0 +1,73 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.normal;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastNormalMsgNotRecvIT extends BaseBroadCastIT {
+    private static Logger logger = Logger
+        .getLogger(NormalMsgTwoSameGroupConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        printSeperator();
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testNotConsumeAfterConsume() {
+        int msgSize = 16;
+
+        String group = initConsumerGroup();
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, group, topic, "*",
+            new RMQNormalListner(group + "_1"));
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, "*", new RMQNormalListner(group + "_2"));
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), waitTime);
+        assertThat(consumer2.getListner().getAllMsgBody().size()).isEqualTo(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvCrashIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvCrashIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvCrashIT.java
new file mode 100644
index 0000000..b878d09
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvCrashIT.java
@@ -0,0 +1,90 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.normal;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastNormalMsgRecvCrashIT extends BaseBroadCastIT {
+    private static Logger logger = Logger
+        .getLogger(NormalMsgTwoSameGroupConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        printSeperator();
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testStartTwoAndCrashOneLater() {
+        int msgSize = 16;
+
+        String group = initConsumerGroup();
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, group, topic, "*",
+            new RMQNormalListner(group + "_1"));
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, "*", new RMQNormalListner(group + "_2"));
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        consumer2.shutdown();
+
+        producer.clearMsg();
+        consumer1.clearMsg();
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvFailIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvFailIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvFailIT.java
new file mode 100644
index 0000000..26c37f9
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvFailIT.java
@@ -0,0 +1,72 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.normal;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastNormalMsgRecvFailIT extends BaseBroadCastIT {
+    private static Logger logger = Logger
+        .getLogger(NormalMsgTwoSameGroupConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        printSeperator();
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testStartTwoConsumerAndOneConsumerFail() {
+        int msgSize = 16;
+
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, topic, "*",
+            new RMQNormalListner());
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, "*",
+            new RMQNormalListner(ConsumeConcurrentlyStatus.RECONSUME_LATER));
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvStartLaterIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvStartLaterIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvStartLaterIT.java
new file mode 100644
index 0000000..027f648
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgRecvStartLaterIT.java
@@ -0,0 +1,88 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.normal;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastNormalMsgRecvStartLaterIT extends BaseBroadCastIT {
+    private static Logger logger = Logger
+        .getLogger(NormalMsgTwoSameGroupConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        printSeperator();
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testStartOneAndStartAnotherLater() {
+        int msgSize = 16;
+
+        String group = initConsumerGroup();
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, group, topic, "*",
+            new RMQNormalListner(group + "_1"));
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+
+        producer.clearMsg();
+        consumer1.clearMsg();
+
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, "*", new RMQNormalListner(group + "_2"));
+        TestUtils.waitForSeconds(waitTime);
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgTwoDiffGroupRecvIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgTwoDiffGroupRecvIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgTwoDiffGroupRecvIT.java
new file mode 100644
index 0000000..acbaf23
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgTwoDiffGroupRecvIT.java
@@ -0,0 +1,78 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.normal;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastNormalMsgTwoDiffGroupRecvIT extends BaseBroadCastIT {
+    private static Logger logger = Logger
+        .getLogger(NormalMsgTwoSameGroupConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        printSeperator();
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testStartDiffSameGroupConsumer() {
+        int msgSize = 16;
+
+        String group1 = initConsumerGroup();
+        String group2 = initConsumerGroup();
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, group1, topic, "*",
+            new RMQNormalListner(group1 + "_1"));
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr, group2, topic, "*",
+            new RMQNormalListner(group2 + "_2"));
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/NormalMsgTwoSameGroupConsumerIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/NormalMsgTwoSameGroupConsumerIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/NormalMsgTwoSameGroupConsumerIT.java
new file mode 100644
index 0000000..984c941
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/NormalMsgTwoSameGroupConsumerIT.java
@@ -0,0 +1,78 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.normal;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class NormalMsgTwoSameGroupConsumerIT extends BaseBroadCastIT {
+    private static Logger logger = Logger
+        .getLogger(NormalMsgTwoSameGroupConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        printSeperator();
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testStartTwoSameGroupConsumer() {
+        int msgSize = 16;
+
+        String group = initConsumerGroup();
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, group, topic, "*",
+            new RMQNormalListner(group + "_1"));
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, "*", new RMQNormalListner(group + "_2"));
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/order/OrderMsgBroadCastIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/order/OrderMsgBroadCastIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/order/OrderMsgBroadCastIT.java
new file mode 100644
index 0000000..ac8fcf5
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/order/OrderMsgBroadCastIT.java
@@ -0,0 +1,75 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.order;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.order.RMQOrderListener;
+import org.apache.rocketmq.test.message.MessageQueueMsg;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class OrderMsgBroadCastIT extends BaseBroadCastIT {
+    private static Logger logger = Logger.getLogger(OrderMsgBroadCastIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumerSubTag() {
+        int msgSize = 10;
+
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, topic, "*",
+            new RMQOrderListener());
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, "*", new RMQOrderListener());
+        TestUtils.waitForSeconds(waitTime);
+
+        List<MessageQueue> mqs = producer.getMessageQueue();
+        MessageQueueMsg mqMsgs = new MessageQueueMsg(mqs, msgSize);
+        producer.send(mqMsgs.getMsgsWithMQ());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer1.getListner()).getMsgs()))
+            .isEqualTo(true);
+        assertThat(VerifyUtils.verifyOrder(((RMQOrderListener) consumer2.getListner()).getMsgs()))
+            .isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerFilterIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerFilterIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerFilterIT.java
new file mode 100644
index 0000000..a1a2ff7
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerFilterIT.java
@@ -0,0 +1,78 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.tag;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastTwoConsumerFilterIT extends BaseBroadCastIT {
+    private static Logger logger = Logger.getLogger(BroadCastTwoConsumerSubTagIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumerFilter() {
+        int msgSize = 40;
+        String tag1 = "jueyin_tag_1";
+        String tag2 = "jueyin_tag_2";
+
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, topic, tag1,
+            new RMQNormalListner());
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, tag1, new RMQNormalListner());
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(tag2, msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+        producer.clearMsg();
+        producer.send(tag1, msgSize);
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubDiffTagIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubDiffTagIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubDiffTagIT.java
new file mode 100644
index 0000000..5c2e7fc
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubDiffTagIT.java
@@ -0,0 +1,75 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.tag;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastTwoConsumerSubDiffTagIT extends BaseBroadCastIT {
+    private static Logger logger = Logger.getLogger(BroadCastTwoConsumerSubTagIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumerSubDiffTag() {
+        int msgSize = 40;
+        String tag = "jueyin_tag";
+
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, topic, "*",
+            new RMQNormalListner());
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, tag, new RMQNormalListner());
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubTagIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubTagIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubTagIT.java
new file mode 100644
index 0000000..e4510de
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/tag/BroadCastTwoConsumerSubTagIT.java
@@ -0,0 +1,75 @@
+/*
+ * 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.rocketmq.test.client.consumer.broadcast.tag;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class BroadCastTwoConsumerSubTagIT extends BaseBroadCastIT {
+    private static Logger logger = Logger.getLogger(BroadCastTwoConsumerSubTagIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s;", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTwoConsumerSubTag() {
+        int msgSize = 20;
+        String tag = "jueyin_tag";
+
+        RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, topic, tag,
+            new RMQNormalListner());
+        RMQBroadCastConsumer consumer2 = getBroadCastConsumer(nsAddr,
+            consumer1.getConsumerGroup(), topic, tag, new RMQNormalListner());
+        TestUtils.waitForSeconds(waitTime);
+
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+
+        consumer1.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        consumer2.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer1.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer2.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddAndCrashIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddAndCrashIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddAndCrashIT.java
new file mode 100644
index 0000000..303dfa0
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddAndCrashIT.java
@@ -0,0 +1,103 @@
+/*
+ * 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.rocketmq.test.client.consumer.cluster;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.balance.NormalMsgStaticBalanceIT;
+import org.apache.rocketmq.test.client.mq.MQAsyncProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class DynamicAddAndCrashIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testAddOneConsumerAndCrashAfterWhile() {
+        int msgSize = 150;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        MQAsyncProducer asyncDefaultMQProducer = new MQAsyncProducer(producer, msgSize, 100);
+        asyncDefaultMQProducer.start();
+        TestUtils.waitForSeconds(waitTime);
+
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        TestUtils.waitForSeconds(waitTime);
+        consumer2.shutdown();
+
+        asyncDefaultMQProducer.waitSendAll(waitTime * 6);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+
+    @Test
+    public void testAddTwoConsumerAndCrashAfterWhile() {
+        int msgSize = 150;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        MQAsyncProducer asyncDefaultMQProducer = new MQAsyncProducer(producer, msgSize, 100);
+        asyncDefaultMQProducer.start();
+        TestUtils.waitForSeconds(waitTime);
+
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        RMQNormalConsumer consumer3 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        TestUtils.waitForSeconds(waitTime);
+
+        consumer2.shutdown();
+        consumer3.shutdown();
+
+        asyncDefaultMQProducer.waitSendAll(waitTime * 6);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner(), consumer3.getListner());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner(), consumer3.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddConsumerIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddConsumerIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddConsumerIT.java
new file mode 100644
index 0000000..46dbb70
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicAddConsumerIT.java
@@ -0,0 +1,97 @@
+/*
+ * 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.rocketmq.test.client.consumer.cluster;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.balance.NormalMsgStaticBalanceIT;
+import org.apache.rocketmq.test.client.mq.MQAsyncProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class DynamicAddConsumerIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testAddOneConsumer() {
+        int msgSize = 100;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        MQAsyncProducer asyncDefaultMQProducer = new MQAsyncProducer(producer, msgSize, 100);
+        asyncDefaultMQProducer.start();
+        TestUtils.waitForSeconds(waitTime);
+
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+
+        asyncDefaultMQProducer.waitSendAll(waitTime * 6);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+
+    @Test
+    public void testAddTwoConsumer() {
+        int msgSize = 100;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+
+        MQAsyncProducer asyncDefaultMQProducer = new MQAsyncProducer(producer, msgSize, 100);
+        asyncDefaultMQProducer.start();
+        TestUtils.waitForSeconds(waitTime);
+
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        RMQNormalConsumer consumer3 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+
+        asyncDefaultMQProducer.waitSendAll(waitTime * 6);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner(), consumer3.getListner());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner(), consumer3.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicCrashConsumerIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicCrashConsumerIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicCrashConsumerIT.java
new file mode 100644
index 0000000..807f950
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/cluster/DynamicCrashConsumerIT.java
@@ -0,0 +1,100 @@
+/*
+ * 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.rocketmq.test.client.consumer.cluster;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.balance.NormalMsgStaticBalanceIT;
+import org.apache.rocketmq.test.client.mq.MQAsyncProducer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.MQWait;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class DynamicCrashConsumerIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(NormalMsgStaticBalanceIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        logger.info(String.format("use topic: %s !", topic));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testAddOneConsumer() {
+        int msgSize = 100;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+
+        MQAsyncProducer asyncDefaultMQProducer = new MQAsyncProducer(producer, msgSize, 100);
+        asyncDefaultMQProducer.start();
+        TestUtils.waitForSeconds(waitTime);
+
+        consumer2.shutdown();
+
+        asyncDefaultMQProducer.waitSendAll(waitTime * 6);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+
+    @Test
+    public void testAddTwoConsumer() {
+        int msgSize = 100;
+        RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, "*", new RMQNormalListner());
+        RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+        RMQNormalConsumer consumer3 = getConsumer(nsAddr, consumer1.getConsumerGroup(), topic,
+            "*", new RMQNormalListner());
+
+        MQAsyncProducer asyncDefaultMQProducer = new MQAsyncProducer(producer, msgSize, 100);
+        asyncDefaultMQProducer.start();
+        TestUtils.waitForSeconds(waitTime);
+
+        consumer2.shutdown();
+        consumer3.shutdown();
+
+        asyncDefaultMQProducer.waitSendAll(waitTime * 6);
+
+        MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer1.getListner(),
+            consumer2.getListner(), consumer3.getListner());
+
+        boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(),
+            consumer1.getListner(), consumer2.getListner(), consumer3.getListner());
+        assertThat(recvAll).isEqualTo(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/MulTagSubIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/MulTagSubIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/MulTagSubIT.java
new file mode 100644
index 0000000..ecb204e
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/MulTagSubIT.java
@@ -0,0 +1,156 @@
+/*
+ * 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.rocketmq.test.client.consumer.tag;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.factory.TagMessage;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.TestUtils;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class MulTagSubIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        String consumerId = initConsumerGroup();
+        logger.info(String.format("use topic: %s; consumerId: %s !", topic, consumerId));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testSubTwoTabMessageOnsTag() {
+        String tag = "jueyin1";
+        String subExpress = String.format("%s||jueyin2", tag);
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubTwoTabAndMatchOne() {
+        String tag1 = "jueyin1";
+        String tag2 = "jueyin2";
+        String subExpress = String.format("%s||noExistTag", tag2);
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+
+        producer.send(tag1, msgSize);
+        Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
+        List<Object> tag2Msgs = MQMessageFactory.getRMQMessage(tag2, topic, msgSize);
+        producer.send(tag2Msgs);
+        Assert.assertEquals("Not all sent succeeded", msgSize * 2, producer.getAllUndupMsgBody().size());
+
+        consumer.getListner().waitForMessageConsume(MQMessageFactory.getMessageBody(tag2Msgs),
+            consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(MQMessageFactory.getMessageBody(tag2Msgs));
+    }
+
+    @Test
+    public void testSubTwoTabAndMatchTwo() {
+        String tags[] = {"jueyin1", "jueyin2"};
+        String subExpress = String.format("%s||%s", tags[0], tags[1]);
+        int msgSize = 10;
+
+        TagMessage tagMessage = new TagMessage(tags, topic, msgSize);
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+
+        producer.send(tagMessage.getMixedTagMessages());
+        Assert.assertEquals("Not all sent succeeded", msgSize * tags.length,
+            producer.getAllUndupMsgBody().size());
+
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(tagMessage.getAllTagMessageBody());
+    }
+
+    @Test
+    public void testSubThreeTabAndMatchTwo() {
+        String tags[] = {"jueyin1", "jueyin2", "jueyin3"};
+        String subExpress = String.format("%s||%s", tags[0], tags[1]);
+        int msgSize = 10;
+
+        TagMessage tagMessage = new TagMessage(tags, topic, msgSize);
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+
+        producer.send(tagMessage.getMixedTagMessages());
+        Assert.assertEquals("Not all sent succeeded", msgSize * tags.length,
+            producer.getAllUndupMsgBody().size());
+
+        consumer.getListner().waitForMessageConsume(
+            tagMessage.getMessageBodyByTag(tags[0], tags[1]), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody())).containsExactlyElementsIn(
+            tagMessage.getMessageBodyByTag(tags[0], tags[1]));
+    }
+
+    @Test
+    public void testNoMatch() {
+        String tags[] = {"jueyin1", "jueyin2", "jueyin3"};
+        String subExpress = "no_match";
+        int msgSize = 10;
+
+        TagMessage tagMessage = new TagMessage(tags, topic, msgSize);
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+
+        producer.send(tagMessage.getMixedTagMessages());
+        Assert.assertEquals("Not all sent succeeded", msgSize * tags.length,
+            producer.getAllUndupMsgBody().size());
+
+        TestUtils.waitForSeconds(5);
+
+        assertThat(VerifyUtils
+            .getFilterdMessage(producer.getAllMsgBody(), consumer.getListner().getAllMsgBody())
+            .size()).isEqualTo(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/788771a8/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWith1ConsumerIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWith1ConsumerIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWith1ConsumerIT.java
new file mode 100644
index 0000000..f0a1d48
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWith1ConsumerIT.java
@@ -0,0 +1,197 @@
+/*
+ * 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.rocketmq.test.client.consumer.tag;
+
+import java.util.List;
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.factory.MQMessageFactory;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class TagMessageWith1ConsumerIT extends BaseConf {
+    private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
+    private RMQNormalProducer producer = null;
+    private String topic = null;
+
+    @Before
+    public void setUp() {
+        topic = initTopic();
+        String consumerId = initConsumerGroup();
+        logger.info(String.format("use topic: %s; consumerId: %s !", topic, consumerId));
+        producer = getProducer(nsAddr, topic);
+    }
+
+    @After
+    public void tearDown() {
+        super.shutDown();
+    }
+
+    @Test
+    public void testTagSmoke() {
+        String tag = "jueyin";
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, tag, new RMQNormalListner());
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubAllMessageNoTag() {
+        String subExprress = "*";
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExprress,
+            new RMQNormalListner());
+        producer.send(msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubAllMessageWithTag() {
+        String tag = "jueyin";
+        String subExpress = "*";
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubAllMessageWithNullTag() {
+        String tag = null;
+        String subExpress = "*";
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubNullWithTagNull() {
+        String tag = null;
+        String subExpress = null;
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+        producer.send(tag, msgSize);
+        Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubAllWithKindsOfMessage() {
+        String tag1 = null;
+        String tag2 = "jueyin";
+        String subExpress = "*";
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+
+        List<Object> tag1Msgs = MQMessageFactory.getRMQMessage(tag1, topic, msgSize);
+        List<Object> tag2Msgs = MQMessageFactory.getRMQMessage(tag2, topic, msgSize);
+
+        producer.send(tag1Msgs);
+        producer.send(tag2Msgs);
+        producer.send(10);
+        Assert.assertEquals("Not all are sent", msgSize * 3, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubNullWithKindsOfMessage() {
+        String tag1 = null;
+        String tag2 = "jueyin";
+        String subExpress = null;
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+
+        List<Object> tag1Msgs = MQMessageFactory.getRMQMessage(tag1, topic, msgSize);
+        List<Object> tag2Msgs = MQMessageFactory.getRMQMessage(tag2, topic, msgSize);
+
+        producer.send(tag1Msgs);
+        producer.send(tag2Msgs);
+        Assert.assertEquals("Not all are sent", msgSize * 2, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(producer.getAllMsgBody());
+    }
+
+    @Test
+    public void testSubTagWithKindsOfMessage() {
+        String tag1 = null;
+        String tag2 = "jueyin";
+        String subExpress = tag2;
+        int msgSize = 10;
+        RMQNormalConsumer consumer = getConsumer(nsAddr, topic, subExpress,
+            new RMQNormalListner());
+
+        List<Object> tag1Msgs = MQMessageFactory.getRMQMessage(tag1, topic, msgSize);
+        List<Object> tag2Msgs = MQMessageFactory.getRMQMessage(tag2, topic, msgSize);
+
+        producer.send(tag1Msgs);
+        producer.send(tag2Msgs);
+        producer.send(10);
+        Assert.assertEquals("Not all are sent", msgSize * 3, producer.getAllUndupMsgBody().size());
+        consumer.getListner().waitForMessageConsume(MQMessageFactory.getMessageBody(tag2Msgs),
+            consumeTime);
+
+        assertThat(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+            consumer.getListner().getAllMsgBody()))
+            .containsExactlyElementsIn(MQMessageFactory.getMessageBody(tag2Msgs));
+    }
+}


[12/13] incubator-rocketmq git commit: [ROCKETMQ-57] Add unit test for DefaultMQAdminExt

Posted by st...@apache.org.
[ROCKETMQ-57] Add unit test for DefaultMQAdminExt


Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/f8d881ba
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/f8d881ba
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/f8d881ba

Branch: refs/heads/ROCKETMQ-57
Commit: f8d881babe3f8f8810f1303912b2fb0ef2badea0
Parents: 0de84e2
Author: stevenschew <st...@apache.org>
Authored: Fri Jan 20 14:53:43 2017 +0800
Committer: stevenschew <st...@apache.org>
Committed: Fri Jan 20 14:53:43 2017 +0800

----------------------------------------------------------------------
 .../tools/admin/DefaultMQAdminExtTest.java      | 136 ++++++++++++++++++-
 1 file changed, 130 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f8d881ba/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java
----------------------------------------------------------------------
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java
index 5964cd1..da3bd8c 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java
@@ -22,15 +22,21 @@ import org.apache.rocketmq.client.exception.MQClientException;
 import org.apache.rocketmq.client.impl.MQClientAPIImpl;
 import org.apache.rocketmq.client.impl.MQClientManager;
 import org.apache.rocketmq.client.impl.factory.MQClientInstance;
+import org.apache.rocketmq.common.admin.*;
+import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.common.namesrv.NamesrvUtil;
 import org.apache.rocketmq.common.protocol.body.*;
+import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
+import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
 import org.apache.rocketmq.common.protocol.route.BrokerData;
+import org.apache.rocketmq.common.protocol.route.QueueData;
 import org.apache.rocketmq.common.protocol.route.TopicRouteData;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
-import org.apache.rocketmq.remoting.exception.RemotingConnectException;
-import org.apache.rocketmq.remoting.exception.RemotingException;
-import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
-import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.exception.*;
+import org.apache.rocketmq.tools.admin.api.MessageTrack;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -43,8 +49,7 @@ import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -93,6 +98,8 @@ public class DefaultMQAdminExtTest {
         brokerData.setBrokerAddrs(brokerAddrs);
         brokerDatas.add(brokerData);
         topicRouteData.setBrokerDatas(brokerDatas);
+        topicRouteData.setQueueDatas(new ArrayList<QueueData>());
+        topicRouteData.setFilterServerTable(new HashMap<String, List<String>>());
         when(mQClientAPIImpl.getTopicRouteInfoFromNameServer(anyString(), anyLong())).thenReturn(topicRouteData);
 
         HashMap<String, String> result = new HashMap<>();
@@ -105,6 +112,7 @@ public class DefaultMQAdminExtTest {
         brokerAddrTable.put("default-broker", brokerData);
         brokerAddrTable.put("broker-test", new BrokerData());
         clusterInfo.setBrokerAddrTable(brokerAddrTable);
+        clusterInfo.setClusterAddrTable(new HashMap<String, Set<String>>());
         when(mQClientAPIImpl.getBrokerClusterInfo(anyLong())).thenReturn(clusterInfo);
         when(mQClientAPIImpl.cleanExpiredConsumeQueue(anyString(), anyLong())).thenReturn(true);
 
@@ -140,6 +148,52 @@ public class DefaultMQAdminExtTest {
         kv.put("cluster-name", "default-cluster");
         kvTable.setTable(kv);
         when(mQClientAPIImpl.getKVListByNamespace(anyString(), anyLong())).thenReturn(kvTable);
+
+        ConsumeStats consumeStats = new ConsumeStats();
+        consumeStats.setConsumeTps(1234);
+        MessageQueue messageQueue = new MessageQueue();
+        OffsetWrapper offsetWrapper = new OffsetWrapper();
+        HashMap<MessageQueue, OffsetWrapper> stats = new HashMap<>();
+        stats.put(messageQueue, offsetWrapper);
+        consumeStats.setOffsetTable(stats);
+        when(mQClientAPIImpl.getConsumeStats(anyString(), anyString(), anyString(), anyLong())).thenReturn(consumeStats);
+
+        ConsumerConnection consumerConnection = new ConsumerConnection();
+        consumerConnection.setConsumeType(ConsumeType.CONSUME_PASSIVELY);
+        consumerConnection.setMessageModel(MessageModel.CLUSTERING);
+        HashSet<Connection> connections = new HashSet<>();
+        connections.add(new Connection());
+        consumerConnection.setConnectionSet(connections);
+        consumerConnection.setSubscriptionTable(new ConcurrentHashMap<String, SubscriptionData>());
+        consumerConnection.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
+        when(mQClientAPIImpl.getConsumerConnectionList(anyString(), anyString(), anyLong())).thenReturn(consumerConnection);
+
+        ProducerConnection producerConnection = new ProducerConnection();
+        Connection connection = new Connection();
+        connection.setClientAddr("127.0.0.1:9898");
+        connection.setClientId("PID_12345");
+        HashSet<Connection> connectionSet = new HashSet<Connection>();
+        connectionSet.add(connection);
+        producerConnection.setConnectionSet(connectionSet);
+        when(mQClientAPIImpl.getProducerConnectionList(anyString(), anyString(), anyLong())).thenReturn(producerConnection);
+
+        when(mQClientAPIImpl.wipeWritePermOfBroker(anyString(), anyString(), anyLong())).thenReturn(6);
+
+        TopicStatsTable topicStatsTable = new TopicStatsTable();
+        topicStatsTable.setOffsetTable(new HashMap<MessageQueue, TopicOffset>());
+
+        Map<String, Map<MessageQueue, Long>> consumerStatus = new HashMap<>();
+        when(mQClientAPIImpl.invokeBrokerToGetConsumerStatus(anyString(), anyString(), anyString(), anyString(), anyLong())).thenReturn(consumerStatus);
+
+        List<QueueTimeSpan> queueTimeSpanList = new ArrayList<>();
+        when(mQClientAPIImpl.queryConsumeTimeSpan(anyString(), anyString(), anyString(), anyLong())).thenReturn(queueTimeSpanList);
+
+        ConsumerRunningInfo consumerRunningInfo = new ConsumerRunningInfo();
+        consumerRunningInfo.setJstack("test");
+        consumerRunningInfo.setMqTable(new TreeMap<MessageQueue, ProcessQueueInfo>());
+        consumerRunningInfo.setStatusTable(new TreeMap<String, ConsumeStatus>());
+        consumerRunningInfo.setSubscriptionSet(new TreeSet<SubscriptionData>());
+        when(mQClientAPIImpl.getConsumerRunningInfo(anyString(), anyString(), anyString(), anyBoolean(), anyLong())).thenReturn(consumerRunningInfo);
     }
 
     @After
@@ -191,6 +245,31 @@ public class DefaultMQAdminExtTest {
     }
 
     @Test
+    public void testExamineConsumeStats() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+        ConsumeStats consumeStats = defaultMQAdminExtImpl.examineConsumeStats("default-consumer-group", "unit-test");
+        assertThat(consumeStats.getConsumeTps()).isEqualTo(1234);
+    }
+
+    @Test
+    public void testExamineConsumerConnectionInfo() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+        ConsumerConnection consumerConnection = defaultMQAdminExtImpl.examineConsumerConnectionInfo("default-consumer-group");
+        assertThat(consumerConnection.getConsumeType()).isEqualTo(ConsumeType.CONSUME_PASSIVELY);
+        assertThat(consumerConnection.getMessageModel()).isEqualTo(MessageModel.CLUSTERING);
+    }
+
+    @Test
+    public void testExamineProducerConnectionInfo() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+        ProducerConnection producerConnection = defaultMQAdminExtImpl.examineProducerConnectionInfo("default-producer-group", "unit-test");
+        assertThat(producerConnection.getConnectionSet().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void testWipeWritePermOfBroker() throws InterruptedException, RemotingCommandException, RemotingSendRequestException, RemotingTimeoutException, MQClientException, RemotingConnectException {
+        int result = defaultMQAdminExtImpl.wipeWritePermOfBroker("127.0.0.1:9876", "default-broker");
+        assertThat(result).isEqualTo(6);
+    }
+
+    @Test
     public void testExamineTopicRouteInfo() throws RemotingException, MQClientException, InterruptedException {
         TopicRouteData topicRouteData = defaultMQAdminExtImpl.examineTopicRouteInfo("UnitTest");
         assertThat(topicRouteData.getBrokerDatas().get(0).getBrokerName()).isEqualTo("default-broker");
@@ -225,12 +304,57 @@ public class DefaultMQAdminExtTest {
     }
 
     @Test
+    public void testQueryConsumeTimeSpan() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+        List<QueueTimeSpan> result = defaultMQAdminExtImpl.queryConsumeTimeSpan("unit-test", "default-broker-group");
+        assertThat(result.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void testCleanExpiredConsumerQueue() throws InterruptedException, RemotingTimeoutException, MQClientException, RemotingSendRequestException, RemotingConnectException {
+        boolean result = defaultMQAdminExtImpl.cleanExpiredConsumerQueue("default-cluster");
+        assertThat(result).isFalse();
+    }
+
+    @Test
     public void testCleanExpiredConsumerQueueByAddr() throws InterruptedException, RemotingTimeoutException, MQClientException, RemotingSendRequestException, RemotingConnectException {
         boolean clean = defaultMQAdminExtImpl.cleanExpiredConsumerQueueByAddr("127.0.0.1:10911");
         assertThat(clean).isTrue();
     }
 
     @Test
+    public void testCleanUnusedTopic() throws InterruptedException, RemotingTimeoutException, MQClientException, RemotingSendRequestException, RemotingConnectException {
+        boolean result = defaultMQAdminExtImpl.cleanUnusedTopic("default-cluster");
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void testGetConsumerRunningInfo() throws RemotingException, MQClientException, InterruptedException {
+        ConsumerRunningInfo consumerRunningInfo = defaultMQAdminExtImpl.getConsumerRunningInfo("consumer-group", "cid_123", false);
+        assertThat(consumerRunningInfo.getJstack()).isEqualTo("test");
+    }
+
+    @Test
+    public void testMessageTrackDetail() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+        MessageExt messageExt = new MessageExt();
+        messageExt.setMsgId("msgId");
+        messageExt.setTopic("unit-test");
+        List<MessageTrack> messageTrackList = defaultMQAdminExtImpl.messageTrackDetail(messageExt);
+        assertThat(messageTrackList.size()).isEqualTo(2);
+    }
+
+    @Test
+    public void testGetConsumeStatus() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+        Map<String, Map<MessageQueue, Long>> result = defaultMQAdminExtImpl.getConsumeStatus("unit-test", "default-broker-group", "127.0.0.1:10911");
+        assertThat(result.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void testGetTopicClusterList() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+        Set<String> result = defaultMQAdminExtImpl.getTopicClusterList("unit-test");
+        assertThat(result.size()).isEqualTo(0);
+    }
+
+    @Test
     public void testGetClusterList() throws InterruptedException, RemotingTimeoutException, MQClientException, RemotingSendRequestException, RemotingConnectException {
         Set<String> clusterlist = defaultMQAdminExtImpl.getClusterList("UnitTest");
         assertThat(clusterlist.contains("default-cluster-one")).isTrue();