This is an automated email from the ASF dual-hosted git repository.

jinrongtong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/rocketmq-e2e.git


The following commit(s) were added to refs/heads/master by this push:
     new 998bcfe  [ISSUE #13] Add End-to-end (e2e) test cases for RocketMQ 
Spring client (#14)
998bcfe is described below

commit 998bcfec7012e25987579fd9d0038c69a3387488
Author: yueya <[email protected]>
AuthorDate: Wed Apr 12 11:06:16 2023 +0800

    [ISSUE #13] Add End-to-end (e2e) test cases for RocketMQ Spring client (#14)
    
    * Update README.md
    
    * Update README.md
    
    * Update pom
    
    * End-to-end (e2e) test cases for RocketMQ Spring client support.
    
    ---------
    
    Co-authored-by: 月伢 <[email protected]>
---
 README.md                                          |   2 +-
 java/e2e-spring/pom.xml                            |  80 +++++++
 .../org/apache/rocketmq/RocketMQApplication.java   |  20 ++
 .../apache/rocketmq/client/DelayListenerImpl.java  |  45 ++++
 .../org/apache/rocketmq/client/MQAdminTools.java   |  62 +++++
 .../apache/rocketmq/client/NormalListenerImpl.java |  41 ++++
 .../apache/rocketmq/client/OrderListenerImpl.java  |  49 ++++
 .../rocketmq/client/TransactionListenerImpl.java   |  48 ++++
 .../java/org/apache/rocketmq/utils/MQAdmin.java    | 251 +++++++++++++++++++++
 .../org/apache/rocketmq/utils/RandomUtils.java     |  91 ++++++++
 .../java/org/apache/rocketmq/utils/TestUtils.java  | 137 +++++++++++
 .../src/main/resources/application.properties      |  32 +++
 .../org/apache/rocketmq/SpringBootBaseTest.java    |  32 +++
 .../apache/rocketmq/message/DelayMessageTest.java  |  94 ++++++++
 .../apache/rocketmq/message/NormalMessageTest.java | 101 +++++++++
 .../apache/rocketmq/message/OrderMessageTest.java  |  75 ++++++
 .../apache/rocketmq/message/TransMessageTest.java  | 113 ++++++++++
 .../src/test/resources/junit-platform.properties   |  19 ++
 .../e2e-spring/src/test/resources/log4j.properties |  25 ++
 .../e2e-spring/src/test/resources/logback-test.xml |  35 +++
 java/e2e-v4/pom.xml                                |  42 +++-
 .../rocketmq/server/delay/DelayMessageTest.java    |   2 +-
 .../rocketmq/server/normal/NormalMessageTest.java  |   2 +-
 .../rocketmq/server/order/OrderMessageTest.java    |   2 +-
 .../server/transaction/TransactionMessageTest.java |   2 +-
 java/e2e/pom.xml                                   |  39 ++++
 java/pom.xml                                       | 147 ++++++++----
 pom.xml                                            |   1 +
 28 files changed, 1542 insertions(+), 47 deletions(-)

diff --git a/README.md b/README.md
index 5f166dd..d37fc5f 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 ## Apache RocketMQ E2E
 
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
 
-RocketMQ E2E Test
+RocketMQ E2E Test  
 
 ### Test Case Coverage
 * Message Type
diff --git a/java/e2e-spring/pom.xml b/java/e2e-spring/pom.xml
new file mode 100644
index 0000000..c088d86
--- /dev/null
+++ b/java/e2e-spring/pom.xml
@@ -0,0 +1,80 @@
+<!--
+  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="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.rocketmq</groupId>
+        <artifactId>rocketmq-java-test</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>rocketmq-java-spring-boot-e2e</artifactId>
+
+    <properties>
+        <spring.boot.starter.version>2.7.8</spring.boot.starter.version>
+        <rocketmq.spring.boot.version>2.2.3</rocketmq.spring.boot.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.rocketmq</groupId>
+            <artifactId>rocketmq-spring-boot-starter</artifactId>
+            <version>${rocketmq.spring.boot.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.rocketmq</groupId>
+            <artifactId>rocketmq-tools</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <version>${spring.boot.starter.version}</version>
+<!--            <scope>test</scope>-->
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>3.0.2</version>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*.conf</include>
+                    <include>**/*.properties</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+</project>
\ No newline at end of file
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/RocketMQApplication.java 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/RocketMQApplication.java
new file mode 100644
index 0000000..5955f9e
--- /dev/null
+++ b/java/e2e-spring/src/main/java/org/apache/rocketmq/RocketMQApplication.java
@@ -0,0 +1,20 @@
+package org.apache.rocketmq;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class RocketMQApplication {
+    protected static List<String> nameserverIpList = new ArrayList<>();
+    protected static String nameserverPort = "9876";
+
+    public static void main(String[] args) {
+        SpringApplication.run(RocketMQApplication.class, args);
+    }
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/client/DelayListenerImpl.java
 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/DelayListenerImpl.java
new file mode 100644
index 0000000..77535ff
--- /dev/null
+++ 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/DelayListenerImpl.java
@@ -0,0 +1,45 @@
+package org.apache.rocketmq.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.common.attribute.TopicMessageType;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.apache.rocketmq.utils.MQAdmin;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.LinkedList;
+import org.springframework.core.env.Environment;
+@Slf4j
+@Component
+@RocketMQMessageListener(topic = "${rocketmq.test.topic.delay}", consumerGroup 
= "gid-delay-spring-test", selectorExpression = "*")
+public class DelayListenerImpl implements RocketMQListener<MessageExt> {
+
+    //  <MessageId, ReceivedTime>
+    private HashMap<String, Long> receivedMessages = new HashMap<>();
+    private LinkedList<String> receivedMessageIds = new LinkedList<>();
+    private String lastMessage;
+
+    @Override
+    public void onMessage(MessageExt msg) {
+        log.info("Received message: " + msg);
+        lastMessage = msg.getMsgId();
+        receivedMessages.put(msg.getMsgId(), System.currentTimeMillis());
+        receivedMessageIds.add(msg.getMsgId());
+    }
+
+    public String getLastMessage() {
+        return lastMessage;
+    }
+
+    public HashMap<String, Long> getReceivedMessages() {
+        return receivedMessages;
+    }
+
+    public LinkedList<String> getReceivedMessageIds() {
+        return receivedMessageIds;
+    }
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/client/MQAdminTools.java 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/MQAdminTools.java
new file mode 100644
index 0000000..8397377
--- /dev/null
+++ b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/MQAdminTools.java
@@ -0,0 +1,62 @@
+package org.apache.rocketmq.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.common.attribute.TopicMessageType;
+import org.apache.rocketmq.utils.MQAdmin;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Component
+public class MQAdminTools {
+    protected static List<String> nameserverIpList = new ArrayList<>();
+    protected static String nameserverPort = "9876";
+    @Value("${rocketmq.name-server}")
+    private String nameserver;
+    @Value("${rocketmq.cluster}")
+    private String cluster;
+    @Value("${rocketmq.test.topic.normal}")
+    private String normalTopic;
+    @Value("${rocketmq.test.topic.delay}")
+    private String delayTopic;
+    @Value("${rocketmq.test.topic.order}")
+    private String orderTopic;
+    @Value("${rocketmq.test.topic.trans}")
+    private String transTopic;
+
+    @PostConstruct
+    private void init() {
+        MQAdmin.initMQAdminExtInstance(nameserver);
+        boolean result1 = MQAdmin.createTopic(cluster, normalTopic, 8, 
TopicMessageType.NORMAL.getValue());
+        boolean result2 = MQAdmin.createTopic(cluster, delayTopic, 8, 
TopicMessageType.NORMAL.getValue());
+        boolean result3 = MQAdmin.createTopic(cluster, orderTopic, 8, 
TopicMessageType.NORMAL.getValue());
+        boolean result4 = MQAdmin.createTopic(cluster, transTopic, 8, 
TopicMessageType.NORMAL.getValue());
+        log.info("Create topic[{}] {}", normalTopic, result1);
+        log.info("Create topic[{}] {}", normalTopic, result2);
+        log.info("Create topic[{}] {}", normalTopic, result3);
+        log.info("Create topic[{}] {}", normalTopic, result4);
+    }
+
+//    private static void initConnectionInfo() {
+//        String ALL_IP = System.getProperty("ALL_IP");
+//        if (ALL_IP != null) {
+//            String[] allPodInfos = ALL_IP.split(",");
+//            for (String podInfo : allPodInfos) {
+//                if (podInfo.contains("nameserver")) {
+//                    
nameserverIpList.add(podInfo.substring(podInfo.indexOf(":") + 1));
+//                }
+//            }
+//            if (nameserverIpList.isEmpty()) {
+//                log.warn("INIT- Get nameserver from external is empty");
+//            } else {
+//                String namesrvAddr = nameserverIpList.get(0) + ":" + 
nameserverPort;
+//                System.setProperty("rocketmq.name-server", namesrvAddr);
+//            }
+//        }
+//    }
+
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/client/NormalListenerImpl.java
 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/NormalListenerImpl.java
new file mode 100644
index 0000000..fe6ec89
--- /dev/null
+++ 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/NormalListenerImpl.java
@@ -0,0 +1,41 @@
+package org.apache.rocketmq.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+
+@Slf4j
+@Component
+@RocketMQMessageListener(topic = "${rocketmq.test.topic.normal}", 
consumerGroup = "gid-normal-spring-test", selectorExpression = "*")
+public class NormalListenerImpl implements RocketMQListener<MessageExt> {
+
+    private HashMap<String, String> receivedMessages = new HashMap<>();
+    private LinkedList<String> receivedMessageIds = new LinkedList<>();
+    private String lastMessage;
+
+    @Override
+    public void onMessage(MessageExt msg) {
+        log.info("Received message: " + msg);
+        lastMessage = msg.getMsgId();
+        log.info("Received messageId: " + msg.getMsgId());
+        receivedMessages.put(msg.getMsgId(), new String(msg.getBody()));
+        receivedMessageIds.add(msg.getMsgId());
+    }
+
+    public String getLastMessage() {
+        return lastMessage;
+    }
+
+    public HashMap<String, String> getReceivedMessages() {
+        return receivedMessages;
+    }
+
+    public LinkedList<String> getReceivedMessageIds() {
+        return receivedMessageIds;
+    }
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/client/OrderListenerImpl.java
 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/OrderListenerImpl.java
new file mode 100644
index 0000000..1fd473c
--- /dev/null
+++ 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/OrderListenerImpl.java
@@ -0,0 +1,49 @@
+package org.apache.rocketmq.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Component;
+
+import java.util.LinkedList;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Component
+@RocketMQMessageListener(topic = "${rocketmq.test.topic.order}", consumerGroup 
= "gid-order-spring-test", selectorExpression = "*", consumeMode = 
ConsumeMode.ORDERLY)
+public class OrderListenerImpl implements RocketMQListener<MessageExt> {
+
+    private ConcurrentHashMap<String, LinkedList<MessageExt>> messageGroups = 
new ConcurrentHashMap<>();
+    private LinkedList<String> receivedMessageIds = new LinkedList<>();
+    private String lastMessage;
+
+    @Override
+    public void onMessage(MessageExt msg) {
+        log.info("Received message- queueId:{}, msgId:{}, body:{}", 
msg.getQueueId(), msg.getMsgId(), new String(msg.getBody()));
+        lastMessage = msg.getMsgId();
+        String shardingKey = String.valueOf(msg.getQueueId());
+        LinkedList<MessageExt> messages = new LinkedList<>();
+        if (messageGroups.containsKey(shardingKey)) {
+            messages = messageGroups.get(shardingKey);
+            messages.add(msg);
+        } else {
+            messages.add(msg);
+            messageGroups.put(shardingKey, messages);
+        }
+        receivedMessageIds.add(msg.getMsgId());
+    }
+
+    public String getLastMessage() {
+        return lastMessage;
+    }
+
+    public ConcurrentHashMap<String, LinkedList<MessageExt>> 
getMessageGroups() {
+        return messageGroups;
+    }
+
+    public LinkedList<String> getReceivedMessageIds() {
+        return receivedMessageIds;
+    }
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/client/TransactionListenerImpl.java
 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/TransactionListenerImpl.java
new file mode 100644
index 0000000..4b6716a
--- /dev/null
+++ 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/client/TransactionListenerImpl.java
@@ -0,0 +1,48 @@
+package org.apache.rocketmq.client;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
+import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
+import org.springframework.messaging.Message;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+
+@Slf4j
+@Component
+@RocketMQTransactionListener
+public class TransactionListenerImpl implements 
RocketMQLocalTransactionListener {
+
+    private HashMap<String, String> receivedMessages = new HashMap<>();
+    private LinkedList<String> receivedMessageIds = new LinkedList<>();
+    private String lastMessage;
+
+    private RocketMQLocalTransactionState executeState = 
RocketMQLocalTransactionState.COMMIT;
+    private RocketMQLocalTransactionState checkState = 
RocketMQLocalTransactionState.COMMIT;
+
+    @Override
+    public RocketMQLocalTransactionState executeLocalTransaction(Message 
message, Object o) {
+        log.info(message.toString());
+        return executeState;
+    }
+
+    @Override
+    public RocketMQLocalTransactionState checkLocalTransaction(Message 
message) {
+        return checkState;
+    }
+
+    public void setExecuteState(RocketMQLocalTransactionState executeState) {
+        log.info("executor state: {}", executeState);
+        this.executeState = executeState;
+    }
+
+    public void setCheckState(RocketMQLocalTransactionState checkState) {
+        log.info("check state: {}", checkState);
+        this.checkState = checkState;
+    }
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/MQAdmin.java 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/MQAdmin.java
new file mode 100644
index 0000000..2c3e196
--- /dev/null
+++ b/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/MQAdmin.java
@@ -0,0 +1,251 @@
+/*
+ * 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.utils;
+
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.TopicAttributes;
+import org.apache.rocketmq.common.admin.ConsumeStats;
+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;
+import org.junit.jupiter.api.Assertions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+
+public class MQAdmin {
+    private static final Logger log = LoggerFactory.getLogger(MQAdmin.class);
+    public static DefaultMQAdminExt mqAdminExt;
+
+    public static DefaultMQAdminExt initMQAdminExtInstance(String namesrvAddr) 
{
+        mqAdminExt = new DefaultMQAdminExt();
+        mqAdminExt.setInstanceName(UUID.randomUUID().toString());
+        mqAdminExt.setNamesrvAddr(namesrvAddr);
+        try {
+            mqAdminExt.start();
+        } catch (MQClientException e) {
+            e.printStackTrace();
+            System.exit(-1);
+        }
+        return mqAdminExt;
+    }
+
+    public static boolean createTopic(String clusterName, String topic, int 
queueNum) {
+        int defaultWaitTime = 30;
+        Map<String, String> attributes = new HashMap<>();
+        return createTopic(clusterName, topic, queueNum, attributes, 
defaultWaitTime);
+    }
+
+    public static boolean createTopic(String clusterName, String topic, int 
queueNum, String type) {
+        int defaultWaitTime = 30;
+        Map<String, String> attributes = new HashMap<>();
+        attributes.put("+" + 
TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName(), type);
+        return createTopic(clusterName, topic, queueNum, attributes, 
defaultWaitTime);
+    }
+
+    public static boolean createTopic(String clusterName, String topic, int 
queueNum, Map<String, String> attributes,
+        int waitTimeSec) {
+        boolean createResult = false;
+        try {
+            mqAdminExt.createTopic(clusterName, topic, queueNum, attributes);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        long startTime = System.currentTimeMillis();
+        while (!createResult) {
+            createResult = checkTopicExist(mqAdminExt, topic);
+            if (System.currentTimeMillis() - startTime < waitTimeSec * 1000) {
+                TestUtils.waitForMoment(100);
+            } else {
+                log.error(String.format("timeout,but create topic[%s] 
failed!", topic));
+                break;
+            }
+        }
+        if (createResult) {
+            log.info("create topic:{} success", topic);
+        }
+        return createResult;
+    }
+
+    public static boolean createConsumerGroup(String clusterName, String 
groupId, int waitTimeSec) {
+        boolean createResult = false;
+        try {
+            SubscriptionGroupConfig subscriptionGroupConfig = new 
SubscriptionGroupConfig();
+            subscriptionGroupConfig.setConsumeBroadcastEnable(false);
+            subscriptionGroupConfig.setConsumeFromMinEnable(false);
+            subscriptionGroupConfig.setGroupName(groupId);
+            subscriptionGroupConfig.setConsumeMessageOrderly(true);
+
+            Set<String> masterSet = 
CommandUtil.fetchMasterAddrByClusterName(mqAdminExt, clusterName);
+            for (String addr : masterSet) {
+                mqAdminExt.createAndUpdateSubscriptionGroupConfig(addr, 
subscriptionGroupConfig);
+                log.info(String.format("create subscription group %s to %s 
success.\n", groupId, addr));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            Assertions.fail(String.format("create groupId:%s failed", 
groupId));
+        }
+//        long startTime = System.currentTimeMillis();
+//        while (!createResult) {
+//            createResult = checkConsumerGroupExist(mqAdminExt, groupId);
+//            if (System.currentTimeMillis() - startTime < waitTimeSec * 1000) 
{
+//                TestUtils.waitForMoment(100);
+//            } else {
+//                log.error(String.format("timeout,but create consumeGroup[%s] 
failed!", groupId));
+//                break;
+//            }
+//        }
+//        if (createResult) {
+//            log.info("create consumeGroup:{} success", groupId);
+//        }
+        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 resetOffsetByTimestamp(String consumerGroup, String 
topic, long timestamp) {
+        boolean result = false;
+        try {
+            mqAdminExt.resetOffsetByTimestamp(topic, consumerGroup, timestamp, 
true);
+            result = true;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    private static boolean checkConsumerGroupExist(DefaultMQAdminExt 
mqAdminExt, String consumerGroup) {
+        boolean createResult = false;
+        try {
+            ConsumeStats consumeStats = 
mqAdminExt.examineConsumeStats(consumerGroup);
+            createResult = !consumeStats.getOffsetTable().isEmpty();
+        } catch (Exception e) {
+        }
+        return createResult;
+    }
+
+    public static boolean createSub(String nameSrvAddr, String clusterName, 
String consumerId) {
+        boolean createResult = true;
+        SubscriptionGroupConfig config = new SubscriptionGroupConfig();
+        config.setGroupName(consumerId);
+        try {
+            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();
+        }
+        return createResult;
+    }
+
+    public static ClusterInfo getCluster(String nameSrvAddr) {
+        ClusterInfo clusterInfo = null;
+        try {
+            clusterInfo = mqAdminExt.examineBrokerClusterInfo();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return clusterInfo;
+    }
+
+    public static boolean isBrokerExist(String ns, String ip) {
+        ClusterInfo clusterInfo = getCluster(ns);
+        if (clusterInfo == null) {
+            return false;
+        } else {
+            Map<String, BrokerData> brokers = clusterInfo.getBrokerAddrTable();
+            for (Entry<String, BrokerData> brokerEntry : brokers.entrySet()) {
+                HashMap<Long, String> brokerIps = 
brokerEntry.getValue().getBrokerAddrs();
+                for (Entry<Long, String> brokerIdEntry : brokerIps.entrySet()) 
{
+                    if (brokerIdEntry.getValue().contains(ip)) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public static void deleteTopic(String nameSrvAddr, String cluster, String 
topic) {
+        try {
+            Set<String> set = new HashSet<>();
+            set.add(nameSrvAddr);
+            mqAdminExt.deleteTopicInNameServer(set, topic);
+
+            boolean isTopicExist = checkTopicExist(mqAdminExt, topic);
+            long startTime = System.currentTimeMillis();
+            while (!isTopicExist) {
+                isTopicExist = checkTopicExist(mqAdminExt, topic);
+                if (System.currentTimeMillis() - startTime < 5 * 1000) {
+                    TestUtils.waitForMoment(100);
+                } else {
+                    log.error(String.format("timeout,but delete topic[%s] 
failed!", topic));
+                    break;
+                }
+            }
+
+        } catch (Exception e) {
+        }
+    }
+
+    public void getSubConnection(String nameSrvAddr, String clusterName, 
String consumerId) {
+        SubscriptionGroupConfig config = new SubscriptionGroupConfig();
+        config.setGroupName(consumerId);
+        try {
+            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) {
+            e.printStackTrace();
+        }
+    }
+
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/RandomUtils.java 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/RandomUtils.java
new file mode 100644
index 0000000..a5e2ef2
--- /dev/null
+++ b/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/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.utils;
+
+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 getChineseWord(int len) {
+        StringBuilder res = new StringBuilder();
+
+        for (int i = 0; i < len; ++i) {
+            char str = getChineseChar();
+            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 getChineseChar() {
+        return (char) (UNICODE_START + rd.nextInt(UNICODE_END - 
UNICODE_START));
+    }
+}
diff --git 
a/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/TestUtils.java 
b/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/TestUtils.java
new file mode 100644
index 0000000..56efa3a
--- /dev/null
+++ b/java/e2e-spring/src/main/java/org/apache/rocketmq/utils/TestUtils.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.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class TestUtils {
+    private static final Logger log = LoggerFactory.getLogger(TestUtils.class);
+
+    private TestUtils() {
+    }
+
+    public static Long parseStringToLong(String s, Long defval) {
+        Long val;
+        try {
+            val = Long.parseLong(s);
+        } catch (NumberFormatException var4) {
+            val = defval;
+        }
+
+        return val;
+    }
+
+    public static Integer parseStringToInteger(String s, Integer defval) {
+        Integer val;
+        try {
+            val = Integer.parseInt(s);
+        } catch (NumberFormatException var4) {
+            val = defval;
+        }
+
+        return val;
+    }
+
+    public static String addQuoteToParamater(String param) {
+        StringBuilder sb = new StringBuilder("'");
+        sb.append(param).append("'");
+        return sb.toString();
+    }
+
+    public static void waitForMoment(long time) {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException var3) {
+            var3.printStackTrace();
+        }
+
+    }
+
+    public static void waitForSeconds(long time) {
+        try {
+            log.info("waiting {} seconds...", time);
+            TimeUnit.SECONDS.sleep(time);
+        } catch (InterruptedException var3) {
+            var3.printStackTrace();
+        }
+
+    }
+
+    public static void waitForMinutes(long time) {
+        try {
+            log.info("waiting {} minutes...", time);
+            TimeUnit.MINUTES.sleep(time);
+        } catch (InterruptedException var3) {
+            var3.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);
+
+            for (String s = (new String(b, 0, n - 1)).replace("\r", 
"").replace("\n", ""); !s.equals(keyWord); s = new String(b, 0, n - 1)) {
+                n = System.in.read(b);
+            }
+        } catch (IOException var5) {
+            var5.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.entrySet());
+        Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
+            @Override
+            public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
+                return ((Comparable) o1.getValue()).compareTo(o2.getValue());
+            }
+        });
+        Map<K, V> result = new LinkedHashMap();
+        Iterator var3 = list.iterator();
+
+        while (var3.hasNext()) {
+            Map.Entry<K, V> entry = (Map.Entry) var3.next();
+            result.put(entry.getKey(), entry.getValue());
+        }
+
+        return result;
+    }
+
+}
diff --git a/java/e2e-spring/src/main/resources/application.properties 
b/java/e2e-spring/src/main/resources/application.properties
new file mode 100644
index 0000000..e9fbab9
--- /dev/null
+++ b/java/e2e-spring/src/main/resources/application.properties
@@ -0,0 +1,32 @@
+# 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.
+
+spring.application.name=rocketmq-spring-e2e-test
+
+rocketmq.name-server=127.0.0.1:9876
+rocketmq.producer.group=my-group
+rocketmq.cluster=DefaultCluster
+# When set rocketmq.pull-consumer.group and rocketmq.pull-consumer.topic, 
rocketmqTemplate will start lite pull consumer
+# If you do not want to use lite pull consumer, please do not set 
rocketmq.pull-consumer.group and rocketmq.pull-consumer.topic
+#rocketmq.pull-consumer.group=my-group1
+#rocketmq.pull-consumer.topic=test
+# another nameserver different global
+rocketmq.test.topic.normal=topic-normal-spring-test
+rocketmq.test.topic.order=topic-order-spring-test
+rocketmq.test.topic.delay=topic-delay-spring-test
+rocketmq.test.topic.trans=topic-trans-spring-test
+rocketmq.pull-consumer.tlsEnable=false
+# ext rocketmq consumer template TLS
+#demo.ext.consumer.tlsEnable=false
diff --git 
a/java/e2e-spring/src/test/java/org/apache/rocketmq/SpringBootBaseTest.java 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/SpringBootBaseTest.java
new file mode 100644
index 0000000..c27b77a
--- /dev/null
+++ b/java/e2e-spring/src/test/java/org/apache/rocketmq/SpringBootBaseTest.java
@@ -0,0 +1,32 @@
+package org.apache.rocketmq;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.utils.MQAdmin;
+import org.apache.rocketmq.utils.RandomUtils;
+import org.junit.jupiter.api.Assertions;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+
+
+@Slf4j
+@SpringBootTest(classes = RocketMQApplication.class)
+public class SpringBootBaseTest {
+    protected static String ALL_IP;
+    @Value("${rocketmq.cluster}")
+    private String cluster;
+
+    protected String getTopic(String messageType, String methodName) {
+        String topic = String.format("topic_%s_%s_%s", messageType, 
methodName, RandomUtils.getStringWithCharacter(6));
+        log.info("[Topic] topic:{}, messageType:{}, methodName:{}", topic, 
messageType, methodName);
+        boolean result = MQAdmin.createTopic(cluster, topic, 8, messageType);
+        Assertions.assertTrue(result, String.format("Create topic:%s failed", 
topic));
+        return topic;
+    }
+
+    protected String getGroupId(String methodName) {
+        String groupId = String.format("GID_%s_%s", methodName, 
RandomUtils.getStringWithCharacter(6));
+        log.info("[ConsumerGroupId] groupId:{}, methodName:{}", groupId, 
methodName);
+        return groupId;
+    }
+
+}
diff --git 
a/java/e2e-spring/src/test/java/org/apache/rocketmq/message/DelayMessageTest.java
 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/DelayMessageTest.java
new file mode 100644
index 0000000..3f67718
--- /dev/null
+++ 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/DelayMessageTest.java
@@ -0,0 +1,94 @@
+package org.apache.rocketmq.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.SpringBootBaseTest;
+import org.apache.rocketmq.client.DelayListenerImpl;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.concurrent.Callable;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.awaitility.Awaitility.await;
+
+@Slf4j
+public class DelayMessageTest extends SpringBootBaseTest {
+
+    @Autowired
+    private RocketMQTemplate rocketMQTemplate;
+    @Autowired
+    private DelayListenerImpl listener;
+    @Value("${rocketmq.test.topic.delay}")
+    private String delayTopic;
+
+    @Test
+    public void testDelayMessage() {
+        int delaySeconds = 10;
+        String message = "Hello, RocketMQ!";
+        SendResult sendResult = 
rocketMQTemplate.syncSendDelayTimeMills(delayTopic, message, delaySeconds * 
1000);
+        log.info("Send delay message: " + sendResult.getMsgId());
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+
+        Long sendTime = System.currentTimeMillis();
+        await().atMost(20, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                boolean result = false;
+                if 
(listener.getReceivedMessageIds().contains(sendResult.getMsgId())) {
+                    Long receivedTime = 
listener.getReceivedMessages().get(sendResult.getMsgId());
+                    if (Math.abs((receivedTime - sendTime) / 1000) - 
delaySeconds < 5) {
+                        result = true;
+                    } else {
+                        log.warn("Inaccurate delay time");
+                    }
+                }
+                return result;
+            }
+        });
+    }
+
+    @Test
+    public void testDeliverTimeMessage() {
+        int delaySeconds = 10;
+        String message = "Hello, RocketMQ!";
+        SendResult sendResult = 
rocketMQTemplate.syncSendDeliverTimeMills(delayTopic, message, 
System.currentTimeMillis() + delaySeconds * 1000);
+        log.info("Send deliverTime message: " + sendResult.getMsgId());
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+
+        Long sendTime = System.currentTimeMillis();
+        await().atMost(20, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                boolean result = false;
+                if 
(listener.getReceivedMessageIds().contains(sendResult.getMsgId())) {
+                    Long receivedTime = 
listener.getReceivedMessages().get(sendResult.getMsgId());
+                    if (Math.abs((receivedTime - sendTime) / 1000) - 
delaySeconds < 5) {
+                        result = true;
+                    } else {
+                        log.warn("Inaccurate delay time");
+                    }
+                }
+                return result;
+            }
+        });
+    }
+
+
+    @Data
+    @AllArgsConstructor
+    public class OrderPaidEvent implements Serializable {
+        private String orderId;
+
+        private BigDecimal paidMoney;
+    }
+
+}
diff --git 
a/java/e2e-spring/src/test/java/org/apache/rocketmq/message/NormalMessageTest.java
 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/NormalMessageTest.java
new file mode 100644
index 0000000..de661d5
--- /dev/null
+++ 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/NormalMessageTest.java
@@ -0,0 +1,101 @@
+package org.apache.rocketmq.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.SpringBootBaseTest;
+import org.apache.rocketmq.client.NormalListenerImpl;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.messaging.support.MessageBuilder;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.concurrent.Callable;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.awaitility.Awaitility.await;
+
+@Slf4j
+public class NormalMessageTest extends SpringBootBaseTest {
+
+    @Autowired
+    private RocketMQTemplate rocketMQTemplate;
+    @Autowired
+    private NormalListenerImpl consumer;
+    @Value("${rocketmq.test.topic.normal}")
+    private String normalTopic;
+
+    @Test
+    public void testSendMessage() {
+        String message = "Hello, RocketMQ!";
+        SendResult sendResult = rocketMQTemplate.syncSend(normalTopic, 
MessageBuilder.withPayload(message).build());
+        log.info(sendResult.getMsgId());
+        Assertions.assertNotNull(sendResult);
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+        await().atMost(10, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return 
consumer.getReceivedMessageIds().contains(sendResult.getMsgId());
+            }
+        });
+    }
+
+    @Test
+    public void testAsyncSendMessage() {
+        final String[] messageId = {""};
+        rocketMQTemplate.asyncSend(normalTopic, new OrderPaidEvent("T_001", 
new BigDecimal("88.00")), new SendCallback() {
+            @Override
+            public void onSuccess(SendResult sendResult) {
+                log.info(sendResult.getMsgId());
+                messageId[0] = sendResult.getMsgId();
+            }
+
+            @Override
+            public void onException(Throwable throwable) {
+                log.warn(throwable.getMessage());
+            }
+        });
+        await().atMost(10, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return consumer.getReceivedMessageIds().contains(messageId[0]);
+            }
+        });
+    }
+
+    @Test
+    public void testConvertAndSend() {
+        String message = "Hello, RocketMQ!";
+        rocketMQTemplate.convertAndSend(normalTopic, message);
+    }
+
+    @Test
+    public void testSendOrderly() {
+        SendResult sendResult = rocketMQTemplate.syncSendOrderly(normalTopic, 
new OrderPaidEvent("T_001", new BigDecimal("88.00")), "test");
+        log.info(sendResult.getMsgId());
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+        await().atMost(10, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return 
consumer.getReceivedMessageIds().contains(sendResult.getMsgId());
+            }
+        });
+    }
+
+
+    @Data
+    @AllArgsConstructor
+    public class OrderPaidEvent implements Serializable {
+        private String orderId;
+
+        private BigDecimal paidMoney;
+    }
+
+}
diff --git 
a/java/e2e-spring/src/test/java/org/apache/rocketmq/message/OrderMessageTest.java
 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/OrderMessageTest.java
new file mode 100644
index 0000000..547eb45
--- /dev/null
+++ 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/OrderMessageTest.java
@@ -0,0 +1,75 @@
+package org.apache.rocketmq.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.SpringBootBaseTest;
+import org.apache.rocketmq.client.NormalListenerImpl;
+import org.apache.rocketmq.client.OrderListenerImpl;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.messaging.support.MessageBuilder;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.awaitility.Awaitility.await;
+
+@Slf4j
+public class OrderMessageTest extends SpringBootBaseTest {
+
+    @Autowired
+    private RocketMQTemplate rocketMQTemplate;
+    @Autowired
+    private OrderListenerImpl listener;
+    @Value("${rocketmq.test.topic.order}")
+    private String orderTopic;
+
+    @Test
+    public void testSendOrderly() {
+        int msgSize = 50;
+        for (int i = 0; i < msgSize; i++) {
+            String hash = String.valueOf(i % 5);
+            SendResult sendResult = 
rocketMQTemplate.syncSendOrderly(orderTopic, i, hash);
+            log.info("Send msgId:{}, queue:{}, hash:{}", 
sendResult.getMsgId(), sendResult.getMessageQueue(), hash);
+            Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+        }
+        await().atMost(30, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return checkOrderMessage(listener.getMessageGroups());
+            }
+        });
+    }
+
+    public static boolean checkOrderMessage(ConcurrentHashMap<String, 
LinkedList<MessageExt>> receivedMessage) {
+        for (Map.Entry<String, LinkedList<MessageExt>> stringLinkedListEntry : 
receivedMessage.entrySet()) {
+            StringBuilder sb = new StringBuilder(String.format("shardingKey 
%s,message order: ", stringLinkedListEntry.getKey()));
+            int preNode = -1;
+            LinkedList<MessageExt> messages = stringLinkedListEntry.getValue();
+            for (MessageExt message : messages) {
+                int curNode = Integer.parseInt(new String(message.getBody()));
+                sb.append(curNode).append(",");
+                if (preNode > curNode) {
+                    log.error(sb.toString());
+                    return false;
+                }
+                preNode = curNode;
+            }
+        }
+        return true;
+    }
+}
diff --git 
a/java/e2e-spring/src/test/java/org/apache/rocketmq/message/TransMessageTest.java
 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/TransMessageTest.java
new file mode 100644
index 0000000..fd80d51
--- /dev/null
+++ 
b/java/e2e-spring/src/test/java/org/apache/rocketmq/message/TransMessageTest.java
@@ -0,0 +1,113 @@
+package org.apache.rocketmq.message;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.SpringBootBaseTest;
+import org.apache.rocketmq.client.NormalListenerImpl;
+import org.apache.rocketmq.client.TransactionListenerImpl;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.awaitility.core.ConditionTimeoutException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.messaging.support.MessageBuilder;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.util.concurrent.Callable;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@Slf4j
+public class TransMessageTest extends SpringBootBaseTest {
+
+    @Autowired
+    private RocketMQTemplate rocketMQTemplate;
+    @Autowired
+    private NormalListenerImpl consumer;
+    @Autowired
+    private TransactionListenerImpl transactionListener;
+    @Value("${rocketmq.test.topic.normal}")
+    private String normalTopic;
+
+    @Test
+    public void testTransExecuteCommitMessage() {
+        String message = "Hello, RocketMQ!";
+        
transactionListener.setExecuteState(RocketMQLocalTransactionState.COMMIT);
+        SendResult sendResult = 
rocketMQTemplate.sendMessageInTransaction(normalTopic, 
MessageBuilder.withPayload(message).build(), null);
+        log.info(sendResult.getMsgId());
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+        Assertions.assertNotNull(sendResult.getTransactionId());
+        await().atMost(10, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return 
consumer.getReceivedMessageIds().contains(sendResult.getMsgId());
+            }
+        });
+    }
+
+    @Test
+    public void testTransExecuteRollbackMessage() {
+        String message = "Hello, RocketMQ!";
+        
transactionListener.setExecuteState(RocketMQLocalTransactionState.ROLLBACK);
+        SendResult sendResult = 
rocketMQTemplate.sendMessageInTransaction(normalTopic, 
MessageBuilder.withPayload(message).build(), null);
+        log.info(sendResult.getMsgId());
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+        Assertions.assertNotNull(sendResult.getTransactionId());
+
+        assertThrows(ConditionTimeoutException.class, () -> {
+            await().atLeast(10, SECONDS).until(new Callable<Boolean>() {
+                @Override
+                public Boolean call() {
+                    return 
consumer.getReceivedMessageIds().contains(sendResult.getMsgId());
+                }
+            });
+        }, "Expected ConditionTimeoutException to throw, but it didn't");
+    }
+
+    @Test
+    public void testTransExecuteUnknowAndCheckCOMMITMessage() {
+        String message = "Hello, RocketMQ!";
+        
transactionListener.setExecuteState(RocketMQLocalTransactionState.UNKNOWN);
+        
transactionListener.setCheckState(RocketMQLocalTransactionState.COMMIT);
+        SendResult sendResult = 
rocketMQTemplate.sendMessageInTransaction(normalTopic, 
MessageBuilder.withPayload(message).build(), null);
+        log.info(sendResult.getMsgId());
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+        Assertions.assertNotNull(sendResult.getTransactionId());
+        await().atMost(30, SECONDS).until(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return 
consumer.getReceivedMessageIds().contains(sendResult.getMsgId());
+            }
+        });
+    }
+
+    @Test
+    public void testTransExecuteUnknowAndCheckRollbackMessage() {
+        String message = "Hello, RocketMQ!";
+        
transactionListener.setExecuteState(RocketMQLocalTransactionState.UNKNOWN);
+        
transactionListener.setCheckState(RocketMQLocalTransactionState.ROLLBACK);
+        SendResult sendResult = 
rocketMQTemplate.sendMessageInTransaction(normalTopic, 
MessageBuilder.withPayload(message).build(), null);
+        log.info(sendResult.getMsgId());
+        Assertions.assertEquals(sendResult.getSendStatus(), 
SendStatus.SEND_OK);
+        Assertions.assertNotNull(sendResult.getTransactionId());
+
+        assertThrows(ConditionTimeoutException.class, () -> {
+            await().atLeast(10, SECONDS).until(new Callable<Boolean>() {
+                @Override
+                public Boolean call() {
+                    return 
consumer.getReceivedMessageIds().contains(sendResult.getMsgId());
+                }
+            });
+        }, "Expected ConditionTimeoutException to throw, but it didn't");
+    }
+}
diff --git a/java/e2e-spring/src/test/resources/junit-platform.properties 
b/java/e2e-spring/src/test/resources/junit-platform.properties
new file mode 100644
index 0000000..97d8151
--- /dev/null
+++ b/java/e2e-spring/src/test/resources/junit-platform.properties
@@ -0,0 +1,19 @@
+# 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.
+
+junit.jupiter.execution.parallel.enabled=true
+junit.jupiter.execution.parallel.mode.default=concurrent
+junit.jupiter.execution.parallel.mode.classes.default=concurrent
+junit.jupiter.execution.parallel.config.dynamic.factor=1
\ No newline at end of file
diff --git a/java/e2e-spring/src/test/resources/log4j.properties 
b/java/e2e-spring/src/test/resources/log4j.properties
new file mode 100644
index 0000000..1398339
--- /dev/null
+++ b/java/e2e-spring/src/test/resources/log4j.properties
@@ -0,0 +1,25 @@
+# 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.
+
+log4j.rootLogger=INFO, stdout
+#log4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender
+#log4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd
+##log4j.appender.ServerDailyRollingFile.File=${log.base}/logs/mq-server-test.log
+#log4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout
+#log4j.appender.ServerDailyRollingFile.layout.ConversionPattern=%d - %m%n
+#log4j.appender.ServerDailyRollingFile.Append=true
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} %p 
[%c.%M:%L] %m%n
\ No newline at end of file
diff --git a/java/e2e-spring/src/test/resources/logback-test.xml 
b/java/e2e-spring/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..ce2a862
--- /dev/null
+++ b/java/e2e-spring/src/test/resources/logback-test.xml
@@ -0,0 +1,35 @@
+<?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 debug="false" scan="true" scanPeriod="1 seconds">
+
+    <contextName>logback</contextName>
+    <!-- 输出到控制台 -->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <!--<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level 
[%logger{12}#%M:%L] - %msg%n</pattern>-->
+            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level 
[%-30.30logger{12}#%-20.20M:%4L] %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <root level="debug">
+        <appender-ref ref="CONSOLE" />
+    </root>
+
+</configuration>
\ No newline at end of file
diff --git a/java/e2e-v4/pom.xml b/java/e2e-v4/pom.xml
index 5ae3c84..13874d2 100644
--- a/java/e2e-v4/pom.xml
+++ b/java/e2e-v4/pom.xml
@@ -12,10 +12,8 @@
     <artifactId>rocketmq-java-e2e-v4</artifactId>
 
     <properties>
-        <maven.compiler.source>8</maven.compiler.source>
-        <maven.compiler.target>8</maven.compiler.target>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <rocketmq.client.version>4.9.3</rocketmq.client.version>
+        <junit.jupiter.version>5.7.2</junit.jupiter.version>
     </properties>
 
     <dependencies>
@@ -36,6 +34,44 @@
             <artifactId>rocketmq-tools</artifactId>
             <version>${rocketmq.client.version}</version>
         </dependency>
+
+        <!--junit5-->
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-launcher</artifactId>
+            <version>1.7.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit.jupiter.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>${junit.jupiter.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <version>${junit.jupiter.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>2.0.0-beta1</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.3.0-beta0</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <version>1.3.0-beta0</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/delay/DelayMessageTest.java
 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/delay/DelayMessageTest.java
similarity index 98%
rename from 
java/e2e-v4/src/test/java/com/apache/rocketmq/server/delay/DelayMessageTest.java
rename to 
java/e2e-v4/src/test/java/org/apache/rocketmq/server/delay/DelayMessageTest.java
index 7d8515c..90b1b11 100644
--- 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/delay/DelayMessageTest.java
+++ 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/delay/DelayMessageTest.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.rocketmq.server.delay;
+package org.apache.rocketmq.server.delay;
 
 import org.apache.rocketmq.client.rmq.RMQNormalConsumer;
 import org.apache.rocketmq.client.rmq.RMQNormalProducer;
diff --git 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/normal/NormalMessageTest.java
 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/normal/NormalMessageTest.java
similarity index 99%
rename from 
java/e2e-v4/src/test/java/com/apache/rocketmq/server/normal/NormalMessageTest.java
rename to 
java/e2e-v4/src/test/java/org/apache/rocketmq/server/normal/NormalMessageTest.java
index 9393bde..7506da4 100644
--- 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/normal/NormalMessageTest.java
+++ 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/normal/NormalMessageTest.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.rocketmq.server.normal;
+package org.apache.rocketmq.server.normal;
 
 import org.apache.rocketmq.client.callback.RMQSendCallBack;
 import org.apache.rocketmq.client.rmq.RMQNormalConsumer;
diff --git 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/order/OrderMessageTest.java
 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/order/OrderMessageTest.java
similarity index 98%
rename from 
java/e2e-v4/src/test/java/com/apache/rocketmq/server/order/OrderMessageTest.java
rename to 
java/e2e-v4/src/test/java/org/apache/rocketmq/server/order/OrderMessageTest.java
index 9e7bb1c..26092fa 100644
--- 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/order/OrderMessageTest.java
+++ 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/order/OrderMessageTest.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.rocketmq.server.order;
+package org.apache.rocketmq.server.order;
 
 import org.apache.rocketmq.client.rmq.RMQNormalConsumer;
 import org.apache.rocketmq.client.rmq.RMQNormalProducer;
diff --git 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/transaction/TransactionMessageTest.java
 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/transaction/TransactionMessageTest.java
similarity index 98%
rename from 
java/e2e-v4/src/test/java/com/apache/rocketmq/server/transaction/TransactionMessageTest.java
rename to 
java/e2e-v4/src/test/java/org/apache/rocketmq/server/transaction/TransactionMessageTest.java
index 5721154..ced5929 100644
--- 
a/java/e2e-v4/src/test/java/com/apache/rocketmq/server/transaction/TransactionMessageTest.java
+++ 
b/java/e2e-v4/src/test/java/org/apache/rocketmq/server/transaction/TransactionMessageTest.java
@@ -15,7 +15,7 @@
  *  limitations under the License.
  */
 
-package com.apache.rocketmq.server.transaction;
+package org.apache.rocketmq.server.transaction;
 
 import org.apache.rocketmq.client.producer.LocalTransactionState;
 import org.apache.rocketmq.client.rmq.RMQNormalConsumer;
diff --git a/java/e2e/pom.xml b/java/e2e/pom.xml
index 7a211cb..76ba5bf 100644
--- a/java/e2e/pom.xml
+++ b/java/e2e/pom.xml
@@ -16,6 +16,7 @@
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
         <rocketmqV5.client.version>5.0.3</rocketmqV5.client.version>
+        <junit.jupiter.version>5.7.2</junit.jupiter.version>
     </properties>
 
     <dependencies>
@@ -50,6 +51,44 @@
             <artifactId>awaitility</artifactId>
             <version>4.0.3</version>
         </dependency>
+
+        <!--junit5-->
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-launcher</artifactId>
+            <version>1.7.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit.jupiter.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>${junit.jupiter.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <version>${junit.jupiter.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>2.0.0-beta1</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.3.0-beta0</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <version>1.3.0-beta0</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/java/pom.xml b/java/pom.xml
index 444f170..76ca102 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -11,59 +11,128 @@
     <modules>
         <module>e2e</module>
         <module>e2e-v4</module>
+        <module>e2e-spring</module>
     </modules>
 
     <properties>
         <maven.compiler.source>8</maven.compiler.source>
         <maven.compiler.target>8</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <junit.jupiter.version>5.7.2</junit.jupiter.version>
+
+        <jdk.version>8</jdk.version>
     </properties>
 
 
     <dependencies>
-        <!--junit5-->
-        <dependency>
-            <groupId>org.junit.platform</groupId>
-            <artifactId>junit-platform-launcher</artifactId>
-            <version>1.7.2</version>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-api</artifactId>
-            <version>${junit.jupiter.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-engine</artifactId>
-            <version>${junit.jupiter.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.jupiter</groupId>
-            <artifactId>junit-jupiter-params</artifactId>
-            <version>${junit.jupiter.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>2.0.0-beta1</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>1.3.0-beta0</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-core</artifactId>
-            <version>1.3.0-beta0</version>
-        </dependency>
-
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <version>1.18.8</version>
         </dependency>
     </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <version>2.17</version>
+                <executions>
+                    <execution>
+                        <id>verify</id>
+                        <phase>verify</phase>
+                        <configuration>
+                            
<configLocation>style/rmq_checkstyle.xml</configLocation>
+                            <encoding>UTF-8</encoding>
+                            <consoleOutput>true</consoleOutput>
+                            <failsOnError>true</failsOnError>
+                            
<includeTestSourceDirectory>false</includeTestSourceDirectory>
+                        </configuration>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <version>0.12</version>
+                <configuration>
+                    <excludes>
+                        <exclude>.gitignore</exclude>
+                        <exclude>.travis.yml</exclude>
+                        <exclude>CONTRIBUTING.md</exclude>
+                        <exclude>bin/README.md</exclude>
+                        <exclude>.github/**</exclude>
+                        <exclude>src/test/resources/certs/*</exclude>
+                        <exclude>src/test/**/*.log</exclude>
+                        
<exclude>src/test/resources/META-INF/service/*</exclude>
+                        
<exclude>src/main/resources/META-INF/service/*</exclude>
+                        <exclude>*/target/**</exclude>
+                        <exclude>*/*.iml</exclude>
+                        <exclude>docs/**</exclude>
+                        <exclude>localbin/**</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-eclipse-plugin</artifactId>
+                <version>2.4</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>3.0.0-M5</version>
+                <configuration>
+                    <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
+                    <!--                    
<rerunFailingTestsCount>1</rerunFailingTestsCount>-->
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <version>2.22.2</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.0</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-test-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                
<source>${project.basedir}/src/test/java</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*.conf</include>
+                    <include>**/*.properties</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
 </project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 1023fd7..4d7bd55 100644
--- a/pom.xml
+++ b/pom.xml
@@ -109,6 +109,7 @@
     <build>
         <plugins>
             <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-checkstyle-plugin</artifactId>
                 <version>2.17</version>
                 <executions>

Reply via email to