You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by ji...@apache.org on 2025/12/04 11:09:13 UTC
(rocketmq) branch develop updated: [ISSUE #9396] Use fastjson2 in all modules (#9397)
This is an automated email from the ASF dual-hosted git repository.
jinrongtong pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/rocketmq.git
The following commit(s) were added to refs/heads/develop by this push:
new d7e27d6d69 [ISSUE #9396] Use fastjson2 in all modules (#9397)
d7e27d6d69 is described below
commit d7e27d6d6988a0cd98100097c9207ec0f5a9f83c
Author: yx9o <ya...@163.com>
AuthorDate: Thu Dec 4 19:09:08 2025 +0800
[ISSUE #9396] Use fastjson2 in all modules (#9397)
* Use fastjson2 in all modules
* Update test
* Update test
* Update test
* Add serialization compatibility test tool class
* Update RemotingSerializableCompatTest.java
* Update RemotingSerializableCompatTest.java
* Update RemotingSerializableCompatTest.java
* Update BitSet problem
* Update
* Update
* Update test
* Update test
* Update BUILD.bazel
* Update BUILD.bazel
* Update test
* Update BitSet problem
* Add test
* Add compat test
* merge develop
* Update test
* merge develop
---
broker/BUILD.bazel | 2 -
broker/pom.xml | 4 -
.../broker/config/v1/RocksDBConfigManager.java | 9 +-
.../config/v1/RocksDBConsumerOffsetManager.java | 15 +-
.../config/v1/RocksDBSubscriptionGroupManager.java | 25 +-
.../config/v1/RocksDBTopicConfigManager.java | 15 +-
.../rocketmq/broker/pop/PopConsumerRecord.java | 8 +-
.../rocketmq/broker/pop/PopConsumerService.java | 35 +-
.../pop/orderly/QueueLevelConsumerManager.java | 2 +-
.../broker/processor/AckMessageProcessor.java | 2 +-
.../broker/processor/AdminBrokerProcessor.java | 7 +-
.../processor/ChangeInvisibleTimeProcessor.java | 2 +-
.../broker/processor/PopBufferMergeService.java | 19 +-
.../broker/processor/PopMessageProcessor.java | 29 +-
.../broker/processor/PopReviveService.java | 23 +-
.../broker/topic/TopicQueueMappingManager.java | 8 +-
.../broker/transaction/TransactionMetrics.java | 27 +-
.../rocketmq/broker/RocksDBConfigManagerTest.java | 67 ++
.../broker/client/ConsumerManagerTest.java | 4 +
.../v1/RocksDBSubscriptionGroupManagerTest.java | 120 +++
.../config/v1/RocksDBTopicConfigManagerTest.java | 97 +++
.../broker/pagecache/QueryMessageTransferTest.java | 139 ++++
.../broker/processor/AdminBrokerProcessorTest.java | 84 ++-
.../ChangeInvisibleTimeProcessorTest.java | 83 ++-
.../processor/PopBufferMergeServiceTest.java | 192 ++++-
.../broker/processor/PopMessageProcessorTest.java | 50 +-
.../broker/processor/PopReviveServiceTest.java | 105 ++-
.../subscription/SubscriptionGroupManagerTest.java | 8 +-
.../broker/topic/TopicQueueMappingManagerTest.java | 68 +-
.../transaction/queue/TransactionMetricsTest.java | 59 +-
client/BUILD.bazel | 1 -
.../rocketmq/client/impl/MQClientAPIImpl.java | 2 +-
.../client/impl/factory/MQClientInstance.java | 39 +-
.../rocketmq/client/producer/SendResult.java | 2 +-
.../consumer/DefaultLitePullConsumerTest.java | 25 +-
.../rocketmq/client/impl/MQClientAPIImplTest.java | 18 +
.../client/impl/admin/MqClientAdminImplTest.java | 4 +-
.../client/impl/consumer/PopProcessQueueTest.java | 56 ++
.../client/impl/consumer/ProcessQueueTest.java | 12 +-
.../rocketmq/client/producer/SendResultTest.java | 59 ++
common/BUILD.bazel | 2 -
.../org/apache/rocketmq/common/TopicConfig.java | 11 +-
.../fastjson/GenericMapSuperclassDeserializer.java | 41 +-
.../rocketmq/common/utils/FastJsonSerializer.java | 16 +-
.../GenericMapSuperclassDeserializerTest.java | 104 +++
container/BUILD.bazel | 2 -
controller/BUILD.bazel | 4 +-
.../impl/heartbeat/RaftBrokerHeartBeatManager.java | 4 +-
.../impl/manager/RaftReplicasInfoManager.java | 2 +-
.../impl/RaftBrokerHeartBeatManagerTest.java | 11 +-
.../controller/impl/event/EventSerializerTest.java | 122 +++
.../impl/event/ListEventSerializerTest.java | 93 +++
.../heartbeat/RaftBrokerHeartBeatManagerTest.java | 352 +++++++++
.../impl/manager/RaftReplicasInfoManagerTest.java | 243 ++++++
filter/BUILD.bazel | 1 -
namesrv/BUILD.bazel | 4 +-
.../namesrv/processor/ClientRequestProcessor.java | 12 +-
.../processor/ClientRequestProcessorTest.java | 195 +++++
proxy/BUILD.bazel | 2 -
.../rocketmq/proxy/config/Configuration.java | 2 +-
.../proxy/config/ConfigurationManager.java | 6 +-
.../processor/channel/RemoteChannelSerializer.java | 9 +-
.../remoting/activity/GetTopicRouteActivity.java | 17 +-
.../proxy/remoting/channel/RemotingChannel.java | 15 +-
.../sysmessage/AbstractSystemMessageSyncer.java | 11 +-
.../proxy/service/sysmessage/HeartbeatSyncer.java | 19 +-
.../proxy/config/ConfigurationManagerTest.java | 10 +
...tionManagerTest.java => ConfigurationTest.java} | 35 +-
.../activity/GetTopicRouteActivityTest.java | 171 +++++
remoting/BUILD.bazel | 4 +-
.../remoting/netty/NettyRemotingClient.java | 47 +-
.../protocol/BitSetSerializerDeserializer.java | 47 +-
.../remoting/protocol/RemotingCommand.java | 22 +-
.../remoting/protocol/RemotingSerializable.java | 12 +-
.../rocketmq/remoting/protocol/body/BatchAck.java | 2 +-
.../remoting/protocol/body/RegisterBrokerBody.java | 21 +-
.../remoting/protocol/heartbeat/HeartbeatData.java | 10 +-
.../protocol/heartbeat/SubscriptionData.java | 5 +-
.../protocol/subscription/GroupRetryPolicy.java | 2 +-
.../protocol/RemotingSerializableCompatTest.java | 425 +++++++++++
.../protocol/RemotingSerializableTest.java | 5 +-
.../remoting/protocol/body/BatchAckTest.java | 2 +-
.../statictopic/TopicQueueMappingTest.java | 14 +-
srvutil/BUILD.bazel | 1 -
store/BUILD.bazel | 3 +-
.../java/org/apache/rocketmq/store/pop/AckMsg.java | 2 +-
.../org/apache/rocketmq/store/pop/BatchAckMsg.java | 3 +-
.../apache/rocketmq/store/pop/PopCheckPoint.java | 6 +-
.../store/queue/CombineConsumeQueueStore.java | 2 +-
.../apache/rocketmq/store/timer/TimerMetrics.java | 34 +-
.../org/apache/rocketmq/store/pop/AckMsgTest.java | 2 +-
.../apache/rocketmq/store/pop/BatchAckMsgTest.java | 2 +-
test/BUILD.bazel | 1 -
tieredstore/BUILD.bazel | 4 +-
.../rocketmq/tieredstore/file/FlatMessageFile.java | 2 +-
.../tieredstore/metadata/DefaultMetadataStore.java | 28 +-
.../metadata/entity/FileSegmentMetadata.java | 2 +-
.../tieredstore/metadata/entity/QueueMetadata.java | 2 +-
.../tieredstore/metadata/entity/TopicMetadata.java | 2 +-
tools/BUILD.bazel | 1 -
tools/pom.xml | 4 -
.../tools/admin/DefaultMQAdminExtImpl.java | 2 +-
.../broker/GetColdDataFlowCtrInfoSubCommand.java | 18 +-
.../command/consumer/UpdateSubGroupSubCommand.java | 7 +-
.../tools/command/export/ExportConfigsCommand.java | 20 +-
.../command/export/ExportMetadataCommand.java | 16 +-
.../export/ExportMetadataInRocksDBCommand.java | 17 +-
.../tools/command/export/ExportMetricsCommand.java | 16 +-
.../metadata/RocksDBConfigToJsonCommand.java | 38 +-
.../command/queue/QueryConsumeQueueCommand.java | 5 +-
.../tools/admin/DefaultMQAdminExtImplTest.java | 825 +++++++++++++++++++++
.../ConsumerConnectionSubCommandTest.java | 5 +-
.../ProducerConnectionSubCommandTest.java | 5 +-
.../consumer/ConsumerStatusSubCommandTest.java | 5 +-
.../consumer/GetConsumerConfigSubCommandTest.java | 9 +-
.../command/producer/ProducerSubCommandTest.java | 36 +-
116 files changed, 4176 insertions(+), 609 deletions(-)
diff --git a/broker/BUILD.bazel b/broker/BUILD.bazel
index fdf549d3e5..ffd2bea14c 100644
--- a/broker/BUILD.bazel
+++ b/broker/BUILD.bazel
@@ -31,7 +31,6 @@ java_library(
"//tieredstore",
"@maven//:org_slf4j_slf4j_api",
"@maven//:ch_qos_logback_logback_classic",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_github_luben_zstd_jni",
"@maven//:com_google_guava_guava",
@@ -83,7 +82,6 @@ java_library(
"//remoting",
"//store",
"//tieredstore",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:org_slf4j_slf4j_api",
"@maven//:com_google_guava_guava",
diff --git a/broker/pom.xml b/broker/pom.xml
index 1751852631..b94e596cc5 100644
--- a/broker/pom.xml
+++ b/broker/pom.xml
@@ -66,10 +66,6 @@
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- </dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java
index e4827e2baf..e68cd20a9d 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java
@@ -16,10 +16,7 @@
*/
package org.apache.rocketmq.broker.config.v1;
-import com.alibaba.fastjson.JSON;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.function.BiConsumer;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.config.ConfigRocksDBStorage;
import org.apache.rocketmq.common.constant.LoggerName;
@@ -33,6 +30,10 @@ import org.rocksdb.RocksDBException;
import org.rocksdb.Statistics;
import org.rocksdb.WriteBatch;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.function.BiConsumer;
+
public class RocksDBConfigManager {
protected static final Logger BROKER_LOG = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java
index 6536f90a8d..45e1a2ab23 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java
@@ -16,12 +16,8 @@
*/
package org.apache.rocketmq.broker.config.v1;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentMap;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerPathConfigHelper;
@@ -35,6 +31,11 @@ import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.rocksdb.CompressionType;
import org.rocksdb.WriteBatch;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentMap;
+
public class RocksDBConsumerOffsetManager extends ConsumerOffsetManager {
protected static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -184,7 +185,7 @@ public class RocksDBConsumerOffsetManager extends ConsumerOffsetManager {
byte[] keyBytes = topicGroupName.getBytes(DataConverter.CHARSET_UTF8);
RocksDBOffsetSerializeWrapper wrapper = new RocksDBOffsetSerializeWrapper();
wrapper.setOffsetTable(offsetMap);
- byte[] valueBytes = JSON.toJSONBytes(wrapper, SerializerFeature.BrowserCompatible);
+ byte[] valueBytes = JSON.toJSONBytes(wrapper, JSONWriter.Feature.BrowserCompatible);
rocksDBConfigManager.writeBatchPutOperation(writeBatch, keyBytes, valueBytes);
}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java
index f6ae3a3e59..b4392212a6 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java
@@ -16,16 +16,9 @@
*/
package org.apache.rocketmq.broker.config.v1;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.function.BiConsumer;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerPathConfigHelper;
@@ -35,6 +28,14 @@ import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
import org.rocksdb.CompressionType;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiConsumer;
+
public class RocksDBSubscriptionGroupManager extends SubscriptionGroupManager {
protected transient RocksDBConfigManager rocksDBConfigManager;
@@ -162,7 +163,7 @@ public class RocksDBSubscriptionGroupManager extends SubscriptionGroupManager {
try {
byte[] keyBytes = groupName.getBytes(RocksDBConfigManager.CHARSET);
- byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, SerializerFeature.BrowserCompatible);
+ byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, JSONWriter.Feature.BrowserCompatible);
this.rocksDBConfigManager.put(keyBytes, valueBytes);
} catch (Exception e) {
log.error("kv put sub Failed, {}", subscriptionGroupConfig.toString());
@@ -177,7 +178,7 @@ public class RocksDBSubscriptionGroupManager extends SubscriptionGroupManager {
if (oldConfig == null) {
try {
byte[] keyBytes = groupName.getBytes(RocksDBConfigManager.CHARSET);
- byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, SerializerFeature.BrowserCompatible);
+ byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, JSONWriter.Feature.BrowserCompatible);
this.rocksDBConfigManager.put(keyBytes, valueBytes);
} catch (Exception e) {
log.error("kv put sub Failed, {}", subscriptionGroupConfig.toString());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java
index 4a8d124e9b..96f12e6681 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java
@@ -16,12 +16,8 @@
*/
package org.apache.rocketmq.broker.config.v1;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map;
-import java.util.concurrent.ConcurrentMap;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerPathConfigHelper;
@@ -32,6 +28,11 @@ import org.apache.rocketmq.common.utils.DataConverter;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.rocksdb.CompressionType;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
public class RocksDBTopicConfigManager extends TopicConfigManager {
private static final String VERSION_COLUMN_FAMILY = "topicVersion";
private static final String TOPIC_COLUMN_FAMILY = "topic";
@@ -142,7 +143,7 @@ public class RocksDBTopicConfigManager extends TopicConfigManager {
TopicConfig oldTopicConfig = this.topicConfigTable.put(topicName, topicConfig);
try {
byte[] keyBytes = topicName.getBytes(DataConverter.CHARSET_UTF8);
- byte[] valueBytes = JSON.toJSONBytes(topicConfig, SerializerFeature.BrowserCompatible);
+ byte[] valueBytes = JSON.toJSONBytes(topicConfig, JSONWriter.Feature.BrowserCompatible);
this.rocksDBConfigManager.put(keyBytes, valueBytes);
} catch (Exception e) {
log.error("kv put topic Failed, {}", topicConfig.toString(), e);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java
index 1ee01fea1c..661ace9bcb 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java
@@ -16,9 +16,9 @@
*/
package org.apache.rocketmq.broker.pop;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.annotation.JSONField;
+
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -119,7 +119,7 @@ public class PopConsumerRecord {
}
public static PopConsumerRecord decode(byte[] body) {
- return JSONObject.parseObject(body, PopConsumerRecord.class);
+ return JSON.parseObject(body, PopConsumerRecord.class);
}
public long getPopTime() {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java
index 7678daa1d3..839c96e390 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java
@@ -16,25 +16,9 @@
*/
package org.apache.rocketmq.broker.pop;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch;
-import java.nio.ByteBuffer;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Objects;
-import java.util.Queue;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.rocketmq.broker.BrokerController;
@@ -65,6 +49,23 @@ import org.apache.rocketmq.store.pop.PopCheckPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.nio.ByteBuffer;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
public class PopConsumerService extends ServiceThread {
private static final Logger log = LoggerFactory.getLogger(LoggerName.ROCKETMQ_POP_LOGGER_NAME);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java
index 79bd59fb78..8a5ed6b150 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.broker.pop.orderly;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import java.util.ArrayList;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
index 864f40d296..1334693352 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import java.nio.charset.StandardCharsets;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
index 298e239086..e7333ab91a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
@@ -16,8 +16,9 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
import com.google.common.collect.Sets;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
@@ -2785,7 +2786,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
} else {
ConsumerFilterData filterData = this.brokerController.getConsumerFilterManager()
.get(requestHeader.getTopic(), requestHeader.getConsumerGroup());
- body.setFilterData(JSON.toJSONString(filterData, true));
+ body.setFilterData(JSON.toJSONString(filterData, JSONWriter.Feature.PrettyFormat));
messageFilter = new ExpressionMessageFilter(subscriptionData, filterData,
this.brokerController.getConsumerFilterManager());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
index f104e76a52..332930cd78 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import java.nio.charset.StandardCharsets;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
index 657adaa34d..06d89e047d 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
@@ -16,15 +16,7 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.atomic.AtomicInteger;
+import com.alibaba.fastjson2.JSON;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.KeyBuilder;
import org.apache.rocketmq.common.PopAckConstants;
@@ -43,6 +35,15 @@ import org.apache.rocketmq.store.pop.AckMsg;
import org.apache.rocketmq.store.pop.BatchAckMsg;
import org.apache.rocketmq.store.pop.PopCheckPoint;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.atomic.AtomicInteger;
+
public class PopBufferMergeService extends ServiceThread {
private static final Logger POP_LOGGER = LoggerFactory.getLogger(LoggerName.ROCKETMQ_POP_LOGGER_NAME);
ConcurrentHashMap<String/*mergeKey*/, PopCheckPointWrapper>
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
index 9967955656..3144eb973a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
@@ -16,26 +16,13 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import com.github.benmanes.caffeine.cache.Cache;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.FileRegion;
import io.opentelemetry.api.common.Attributes;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.filter.ConsumerFilterData;
import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
@@ -89,6 +76,20 @@ import org.apache.rocketmq.store.pop.AckMsg;
import org.apache.rocketmq.store.pop.BatchAckMsg;
import org.apache.rocketmq.store.pop.PopCheckPoint;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_CONSUMER_GROUP;
import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_IS_RETRY;
import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_IS_SYSTEM;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
index aa7d87505e..434812883e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
@@ -16,18 +16,8 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import io.opentelemetry.api.common.Attributes;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.TreeMap;
-import java.util.concurrent.CompletableFuture;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.rocketmq.broker.BrokerController;
@@ -59,6 +49,17 @@ import org.apache.rocketmq.store.pop.AckMsg;
import org.apache.rocketmq.store.pop.BatchAckMsg;
import org.apache.rocketmq.store.pop.PopCheckPoint;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+import java.util.concurrent.CompletableFuture;
+
import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_CONSUMER_GROUP;
import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_IS_SYSTEM;
import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_TOPIC;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java
index 4b0714decb..9e20ecd9b6 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java
@@ -16,7 +16,8 @@
*/
package org.apache.rocketmq.broker.topic;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
@@ -156,7 +157,10 @@ public class TopicQueueMappingManager extends ConfigManager {
TopicQueueMappingSerializeWrapper wrapper = new TopicQueueMappingSerializeWrapper();
wrapper.setTopicQueueMappingInfoMap(topicQueueMappingTable);
wrapper.setDataVersion(this.dataVersion);
- return JSON.toJSONString(wrapper, pretty);
+ if (pretty) {
+ return JSON.toJSONString(wrapper, JSONWriter.Feature.PrettyFormat);
+ }
+ return JSON.toJSONString(wrapper);
}
@Override
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java
index 8a18218f53..17b0ac6774 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java
@@ -16,9 +16,19 @@
*/
package org.apache.rocketmq.broker.transaction;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import org.apache.rocketmq.common.ConfigManager;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
import java.io.File;
+import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.io.Writer;
@@ -32,14 +42,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
-import org.apache.rocketmq.common.ConfigManager;
-import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.topic.TopicValidator;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.protocol.DataVersion;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
public class TransactionMetrics extends ConfigManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -90,11 +93,11 @@ public class TransactionMetrics extends ConfigManager {
this.transactionCounts = transactionCounts;
}
- protected void write0(Writer writer) {
+ protected void write0(Writer writer) throws IOException {
TransactionMetricsSerializeWrapper wrapper = new TransactionMetricsSerializeWrapper();
wrapper.setTransactionCount(transactionCounts);
wrapper.setDataVersion(dataVersion);
- JSON.writeJSONString(writer, wrapper, SerializerFeature.BrowserCompatible);
+ writer.write(JSON.toJSONString(wrapper, JSONWriter.Feature.BrowserCompatible));
}
@Override
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/RocksDBConfigManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/RocksDBConfigManagerTest.java
new file mode 100644
index 0000000000..1832902a76
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/RocksDBConfigManagerTest.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.broker;
+
+import org.apache.rocketmq.broker.config.v1.RocksDBConfigManager;
+import org.apache.rocketmq.common.config.ConfigRocksDBStorage;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.mock;
+
+public class RocksDBConfigManagerTest {
+
+ private ConfigRocksDBStorage configRocksDBStorage;
+
+ private RocksDBConfigManager rocksDBConfigManager;
+
+ @Before
+ public void setUp() throws IllegalAccessException {
+ configRocksDBStorage = mock(ConfigRocksDBStorage.class);
+ rocksDBConfigManager = spy(new RocksDBConfigManager("testPath", 1000L, null));
+ rocksDBConfigManager.configRocksDBStorage = configRocksDBStorage;
+ }
+
+ @Test
+ public void testLoadDataVersion() throws Exception {
+ DataVersion expected = new DataVersion();
+ expected.nextVersion();
+
+ when(rocksDBConfigManager.getKvDataVersion()).thenReturn(expected);
+
+ boolean result = rocksDBConfigManager.loadDataVersion();
+
+ assertTrue(result);
+ assertEquals(expected.getCounter().get(), rocksDBConfigManager.getKvDataVersion().getCounter().get());
+ assertEquals(expected.getTimestamp(), rocksDBConfigManager.getKvDataVersion().getTimestamp());
+ }
+
+ @Test
+ public void testUpdateKvDataVersion() throws Exception {
+ rocksDBConfigManager.updateKvDataVersion();
+
+ verify(rocksDBConfigManager, times(1)).updateKvDataVersion();
+ }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java
index 1b8293159d..5f2e96015d 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java
@@ -20,6 +20,7 @@ package org.apache.rocketmq.broker.client;
import com.google.common.collect.ImmutableSet;
import io.netty.channel.Channel;
import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.broker.client.net.Broker2Client;
import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
import org.apache.rocketmq.common.BrokerConfig;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
@@ -214,6 +215,9 @@ public class ConsumerManagerTest {
@Test
public void testRegisterConsumerWithoutSub() {
+ when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+ Broker2Client broker2Client = mock(Broker2Client.class);
+ when(brokerController.getBroker2Client()).thenReturn(broker2Client);
ConsumerGroupInfo groupInfo = new ConsumerGroupInfo(GROUP, CONSUME_PASSIVELY,
MessageModel.CLUSTERING, ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
SubscriptionData subscriptionData = new SubscriptionData(TOPIC, "*");
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManagerTest.java
new file mode 100644
index 0000000000..98d0e34219
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManagerTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.broker.config.v1;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RocksDBSubscriptionGroupManagerTest {
+
+ @Mock
+ private BrokerController brokerController;
+
+ @Mock
+ private RocksDBConfigManager rocksDBConfigManager;
+
+ private RocksDBSubscriptionGroupManager rocksDBSubscriptionGroupManager;
+
+ @Mock
+ private MessageStoreConfig messageStoreConfig;
+
+ @Before
+ public void init() throws IllegalAccessException {
+ when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
+ when(messageStoreConfig.getMemTableFlushIntervalMs()).thenReturn(1000L);
+ when(messageStoreConfig.getRocksdbCompressionType()).thenReturn("LZ4_COMPRESSION");
+ when(messageStoreConfig.getStorePathRootDir()).thenReturn("/");
+ BrokerConfig brokerConfig = mock(BrokerConfig.class);
+ when(brokerConfig.isUseSingleRocksDBForAllConfigs()).thenReturn(true);
+ when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+ rocksDBSubscriptionGroupManager = new RocksDBSubscriptionGroupManager(brokerController);
+ FieldUtils.writeDeclaredField(rocksDBSubscriptionGroupManager, "rocksDBConfigManager", rocksDBConfigManager, true);
+ }
+
+ @Test
+ public void testPutSubscriptionGroupConfig() {
+ SubscriptionGroupConfig newConfig = new SubscriptionGroupConfig();
+ newConfig.setGroupName("group");
+ SubscriptionGroupConfig oldConfig = new SubscriptionGroupConfig();
+ oldConfig.setGroupName("group");
+ rocksDBSubscriptionGroupManager.getSubscriptionGroupTable().put("group", oldConfig);
+
+ assertEquals(oldConfig, rocksDBSubscriptionGroupManager.putSubscriptionGroupConfig(newConfig));
+ assertEquals(newConfig, rocksDBSubscriptionGroupManager.getSubscriptionGroupTable().get("group"));
+ }
+
+ @Test
+ public void testPutSubscriptionGroupConfigIfAbsent() {
+ SubscriptionGroupConfig newConfig = new SubscriptionGroupConfig();
+ newConfig.setGroupName("group");
+ SubscriptionGroupConfig oldConfig = new SubscriptionGroupConfig();
+ oldConfig.setGroupName("group");
+
+ assertNull(rocksDBSubscriptionGroupManager.putSubscriptionGroupConfigIfAbsent(newConfig));
+ assertEquals(newConfig, rocksDBSubscriptionGroupManager.getSubscriptionGroupTable().get("group"));
+ }
+
+ @Test
+ public void testDecodeForbidden() {
+ String forbiddenGroupName = "group";
+ String bodyJson = "{\"topic1\":1,\"topic2\":2}";
+ byte[] key = forbiddenGroupName.getBytes(StandardCharsets.UTF_8);
+ byte[] body = bodyJson.getBytes(StandardCharsets.UTF_8);
+
+ rocksDBSubscriptionGroupManager.decodeForbidden(key, body);
+ ConcurrentMap<String, ConcurrentMap<String, Integer>> forbiddenTable = rocksDBSubscriptionGroupManager.getForbiddenTable();
+ assertTrue(forbiddenTable.containsKey(forbiddenGroupName));
+
+ ConcurrentMap<String, Integer> forbiddenGroup = forbiddenTable.get(forbiddenGroupName);
+ assertEquals(2, forbiddenGroup.size());
+ assertEquals(Integer.valueOf(1), forbiddenGroup.get("topic1"));
+ assertEquals(Integer.valueOf(2), forbiddenGroup.get("topic2"));
+ }
+
+ @Test
+ public void testDecodeSubscriptionGroup() {
+ String groupName = "group";
+ String bodyJson = "{\"groupName\":\"group\",\"consumeEnable\":true}";
+ byte[] key = groupName.getBytes(StandardCharsets.UTF_8);
+ byte[] body = bodyJson.getBytes(StandardCharsets.UTF_8);
+
+ rocksDBSubscriptionGroupManager.decodeSubscriptionGroup(key, body);
+ ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable = rocksDBSubscriptionGroupManager.getSubscriptionGroupTable();
+ assertEquals(1, subscriptionGroupTable.size());
+ SubscriptionGroupConfig config = subscriptionGroupTable.get(groupName);
+ assertEquals(groupName, config.getGroupName());
+ assertTrue(config.isConsumeEnable());
+ }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManagerTest.java
new file mode 100644
index 0000000000..b2b742fb2f
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManagerTest.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.broker.config.v1;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RocksDBTopicConfigManagerTest {
+
+ @Mock
+ private BrokerController brokerController;
+
+ @Mock
+ private MessageStoreConfig messageStoreConfig;
+
+ @Mock
+ private RocksDBConfigManager rocksDBConfigManager;
+
+ private RocksDBTopicConfigManager rocksDBTopicConfigManager;
+
+ @Before
+ public void init() throws Exception {
+ when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
+ when(messageStoreConfig.getMemTableFlushIntervalMs()).thenReturn(1000L);
+ when(messageStoreConfig.getRocksdbCompressionType()).thenReturn("LZ4_COMPRESSION");
+ when(messageStoreConfig.getStorePathRootDir()).thenReturn("/");
+ BrokerConfig brokerConfig = mock(BrokerConfig.class);
+ when(brokerConfig.isUseSingleRocksDBForAllConfigs()).thenReturn(true);
+ when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+ rocksDBTopicConfigManager = new RocksDBTopicConfigManager(brokerController);
+ FieldUtils.writeDeclaredField(rocksDBTopicConfigManager, "rocksDBConfigManager", rocksDBConfigManager, true);
+ }
+
+ @Test
+ public void testDecodeTopicConfig() {
+ String topicName = "testTopic";
+ String topicConfigJson = "{\"topicName\":\"testTopic\",\"readQueueNums\":10,\"writeQueueNums\":10}";
+ byte[] key = topicName.getBytes(StandardCharsets.UTF_8);
+ byte[] body = topicConfigJson.getBytes(StandardCharsets.UTF_8);
+
+ rocksDBTopicConfigManager.decodeTopicConfig(key, body);
+
+ ConcurrentMap<String, TopicConfig> topicConfigTable = rocksDBTopicConfigManager.getTopicConfigTable();
+ assertNotNull(topicConfigTable);
+ assertEquals(1, topicConfigTable.size());
+ TopicConfig topicConfig = topicConfigTable.get(topicName);
+ assertNotNull(topicConfig);
+ assertEquals(topicName, topicConfig.getTopicName());
+ assertEquals(10, topicConfig.getReadQueueNums());
+ assertEquals(10, topicConfig.getWriteQueueNums());
+ }
+
+ @Test
+ public void testPutTopicConfig() throws Exception {
+ TopicConfig newTopicConfig = new TopicConfig("newTopic");
+ newTopicConfig.setReadQueueNums(10);
+ newTopicConfig.setWriteQueueNums(10);
+
+ assertNull(rocksDBTopicConfigManager.putTopicConfig(newTopicConfig));
+ verify(rocksDBConfigManager, times(1)).put(any(byte[].class), any(byte[].class));
+ }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransferTest.java b/broker/src/test/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransferTest.java
new file mode 100644
index 0000000000..a10dd4efca
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransferTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.broker.pagecache;
+
+import org.apache.rocketmq.store.QueryMessageResult;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class QueryMessageTransferTest {
+
+ @Mock
+ private WritableByteChannel writableByteChannel;
+
+ @Mock
+ private QueryMessageResult queryMessageResult;
+
+ private QueryMessageTransfer queryMessageTransfer;
+
+ private ByteBuffer byteBufferHeader;
+
+ private ByteBuffer bb1;
+
+ private ByteBuffer bb2;
+
+ @Before
+ public void init() {
+ byteBufferHeader = ByteBuffer.allocate(4);
+ byteBufferHeader.putInt(1);
+ byteBufferHeader.flip();
+
+ bb1 = ByteBuffer.allocate(4);
+ bb1.putInt(2);
+ bb1.flip();
+
+ bb2 = ByteBuffer.allocate(4);
+ bb2.putInt(3);
+ bb2.flip();
+
+ when(queryMessageResult.getMessageBufferList()).thenReturn(Arrays.asList(bb1, bb2));
+
+ queryMessageTransfer = new QueryMessageTransfer(byteBufferHeader, queryMessageResult);
+ }
+
+ @Test
+ public void testPosition_WithHeaderAndMessageBuffers() {
+ byteBufferHeader.position(2);
+ bb1.position(1);
+ bb2.position(3);
+
+ long actual = queryMessageTransfer.position();
+
+ long expected = byteBufferHeader.position() + bb1.position() + bb2.position();
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testPosition_WithHeaderOnly() {
+ byteBufferHeader.position(2);
+
+ when(queryMessageResult.getMessageBufferList()).thenReturn(new ArrayList<>());
+
+ long actual = queryMessageTransfer.position();
+
+ long expected = byteBufferHeader.position();
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testPosition_WithMessageBuffersOnly() {
+ byteBufferHeader.clear();
+ byteBufferHeader.flip();
+
+ bb1.position(1);
+ bb2.position(3);
+
+ long actual = queryMessageTransfer.position();
+
+ long expected = bb1.position() + bb2.position();
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testTransferTo_OnlyHeaderData() throws Exception {
+ bb1.clear();
+ bb2.clear();
+
+ when(writableByteChannel.write(byteBufferHeader)).thenReturn(4);
+
+ long actual = queryMessageTransfer.transferTo(writableByteChannel, 0);
+
+ assertEquals(4, actual);
+ verify(writableByteChannel, times(1)).write(byteBufferHeader);
+ verify(writableByteChannel, never()).write(bb1);
+ verify(writableByteChannel, never()).write(bb2);
+ }
+
+ @Test
+ public void testTransferTo_OnlyMessageBuffersData() throws Exception {
+ byteBufferHeader.clear();
+ byteBufferHeader.flip();
+
+ when(writableByteChannel.write(bb1)).thenReturn(4);
+
+ long actual = queryMessageTransfer.transferTo(writableByteChannel, 0);
+
+ assertEquals(4, actual);
+ verify(writableByteChannel, never()).write(byteBufferHeader);
+ verify(writableByteChannel, times(1)).write(bb1);
+ }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
index 1bf99eadfb..572be63e3f 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
@@ -16,7 +16,8 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -37,11 +38,11 @@ import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
import org.apache.rocketmq.broker.client.ConsumerManager;
import org.apache.rocketmq.broker.client.net.Broker2Client;
+import org.apache.rocketmq.broker.config.v1.RocksDBSubscriptionGroupManager;
+import org.apache.rocketmq.broker.config.v1.RocksDBTopicConfigManager;
import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
import org.apache.rocketmq.broker.offset.ConsumerOffsetManager;
import org.apache.rocketmq.broker.schedule.ScheduleMessageService;
-import org.apache.rocketmq.broker.config.v1.RocksDBSubscriptionGroupManager;
-import org.apache.rocketmq.broker.config.v1.RocksDBTopicConfigManager;
import org.apache.rocketmq.broker.topic.TopicConfigManager;
import org.apache.rocketmq.common.BoundaryType;
import org.apache.rocketmq.common.BrokerConfig;
@@ -80,6 +81,7 @@ import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
import org.apache.rocketmq.remoting.protocol.body.UnlockBatchRequestBody;
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
+import org.apache.rocketmq.remoting.protocol.header.CheckRocksdbCqWriteProgressRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateTopicRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateUserRequestHeader;
@@ -97,11 +99,13 @@ import org.apache.rocketmq.remoting.protocol.header.GetConsumerStatusRequestHead
import org.apache.rocketmq.remoting.protocol.header.GetEarliestMsgStoretimeRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetMaxOffsetRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetMinOffsetRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.GetSubscriptionGroupConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetTopicConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetUserRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ListAclsRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ListUsersRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.NotifyMinBrokerIdChangeRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.QueryConsumeQueueRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.QueryCorrectionOffsetHeader;
import org.apache.rocketmq.remoting.protocol.header.QuerySubscriptionByConsumerRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.QueryTopicConsumeByWhoRequestHeader;
@@ -114,6 +118,8 @@ import org.apache.rocketmq.remoting.protocol.header.UpdateAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateUserRequestHeader;
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.protocol.statictopic.TopicConfigAndQueueMapping;
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.store.CommitLog;
import org.apache.rocketmq.store.DefaultMessageStore;
@@ -121,6 +127,7 @@ import org.apache.rocketmq.store.MessageStore;
import org.apache.rocketmq.store.SelectMappedBufferResult;
import org.apache.rocketmq.store.config.MessageStoreConfig;
import org.apache.rocketmq.store.logfile.DefaultMappedFile;
+import org.apache.rocketmq.store.queue.ConsumeQueueInterface;
import org.apache.rocketmq.store.stats.BrokerStats;
import org.apache.rocketmq.store.timer.TimerCheckpoint;
import org.apache.rocketmq.store.timer.TimerMessageStore;
@@ -159,6 +166,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.LongAdder;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -889,7 +898,7 @@ public class AdminBrokerProcessorTest {
consumerOffsetManager = mock(ConsumerOffsetManager.class);
when(brokerController.getConsumerOffsetManager()).thenReturn(consumerOffsetManager);
ConsumerOffsetManager consumerOffset = new ConsumerOffsetManager();
- when(consumerOffsetManager.encode()).thenReturn(JSON.toJSONString(consumerOffset, false));
+ when(consumerOffsetManager.encode()).thenReturn(JSON.toJSONString(consumerOffset));
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_CONSUMER_OFFSET, null);
RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
@@ -1500,6 +1509,73 @@ public class AdminBrokerProcessorTest {
assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
}
+ @Test
+ public void testGetSubscriptionGroup() throws RemotingCommandException {
+ brokerController.getSubscriptionGroupManager().getSubscriptionGroupTable().put("group", new SubscriptionGroupConfig());
+ GetSubscriptionGroupConfigRequestHeader requestHeader = new GetSubscriptionGroupConfigRequestHeader();
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_SUBSCRIPTIONGROUP_CONFIG, requestHeader);
+ requestHeader.setGroup("group");
+ request.makeCustomHeaderToNet();
+ RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+ }
+
+ @Test
+ public void testCheckRocksdbCqWriteProgress() throws RemotingCommandException {
+ CheckRocksdbCqWriteProgressRequestHeader requestHeader = new CheckRocksdbCqWriteProgressRequestHeader();
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CHECK_ROCKSDB_CQ_WRITE_PROGRESS, requestHeader);
+ requestHeader.setTopic("topic");
+ request.makeCustomHeaderToNet();
+ RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+ }
+
+ @Test
+ public void testQueryConsumeQueue() throws RemotingCommandException {
+ messageStore = mock(MessageStore.class);
+ ConsumeQueueInterface consumeQueue = mock(ConsumeQueueInterface.class);
+ when(consumeQueue.getMinOffsetInQueue()).thenReturn(0L);
+ when(consumeQueue.getMaxOffsetInQueue()).thenReturn(1L);
+ when(messageStore.getConsumeQueue(anyString(), anyInt())).thenReturn(consumeQueue);
+ when(brokerController.getMessageStore()).thenReturn(messageStore);
+ QueryConsumeQueueRequestHeader requestHeader = new QueryConsumeQueueRequestHeader();
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.QUERY_CONSUME_QUEUE, requestHeader);
+ requestHeader.setTopic("topic");
+ requestHeader.setQueueId(0);
+ requestHeader.setConsumerGroup("testGroup");
+ request.makeCustomHeaderToNet();
+ SubscriptionData subscriptionData = mock(SubscriptionData.class);
+ when(brokerController.getConsumerManager()).thenReturn(consumerManager);
+ when(consumerManager.findSubscriptionData(any(), any())).thenReturn(subscriptionData);
+ RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+ }
+
+ @Test
+ public void testProcessRequest_GetTopicConfig() throws Exception {
+ GetTopicConfigRequestHeader requestHeader = new GetTopicConfigRequestHeader();
+ requestHeader.setTopic("testTopic");
+
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_TOPIC_CONFIG, requestHeader);
+ request.makeCustomHeaderToNet();
+
+ TopicConfig topicConfig = new TopicConfig();
+ topicConfig.setTopicName("testTopic");
+ TopicConfigManager topicConfigManager = mock(TopicConfigManager.class);
+ when(brokerController.getTopicConfigManager()).thenReturn(topicConfigManager);
+ when(topicConfigManager.selectTopicConfig("testTopic"))
+ .thenReturn(topicConfig);
+
+ RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+
+ assertNotNull(response);
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+
+ String responseBody = new String(response.getBody(), StandardCharsets.UTF_8);
+ TopicConfigAndQueueMapping result = JSONObject.parseObject(responseBody, TopicConfigAndQueueMapping.class);
+ assertEquals("testTopic", result.getTopicName());
+ }
+
private ResetOffsetRequestHeader createRequestHeader(String topic,String group,long timestamp,boolean force,long offset,int queueId) {
ResetOffsetRequestHeader requestHeader = new ResetOffsetRequestHeader();
requestHeader.setTopic(topic);
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java
index ca2529e319..7afd338dca 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java
@@ -18,18 +18,15 @@ package org.apache.rocketmq.broker.processor;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
-import java.lang.reflect.Field;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.broker.client.net.Broker2Client;
import org.apache.rocketmq.broker.failover.EscapeBridge;
import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
-import org.apache.rocketmq.store.stats.BrokerStatsManager;
+import org.apache.rocketmq.broker.metrics.PopMetricsManager;
+import org.apache.rocketmq.broker.topic.TopicConfigManager;
import org.apache.rocketmq.common.BrokerConfig;
import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.broker.topic.TopicConfigManager;
import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.common.message.MessageExtBrokerInner;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
@@ -41,13 +38,16 @@ import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.ResponseCode;
import org.apache.rocketmq.remoting.protocol.header.ChangeInvisibleTimeRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ExtraInfoUtil;
+import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumerData;
import org.apache.rocketmq.store.AppendMessageResult;
import org.apache.rocketmq.store.AppendMessageStatus;
import org.apache.rocketmq.store.DefaultMessageStore;
+import org.apache.rocketmq.store.MessageStore;
import org.apache.rocketmq.store.PutMessageResult;
import org.apache.rocketmq.store.PutMessageStatus;
import org.apache.rocketmq.store.config.MessageStoreConfig;
import org.apache.rocketmq.store.exception.ConsumeQueueException;
+import org.apache.rocketmq.store.stats.BrokerStatsManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,10 +55,18 @@ import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
+import java.lang.reflect.Field;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.rocketmq.broker.processor.PullMessageProcessorTest.createConsumerData;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -118,6 +126,17 @@ public class ChangeInvisibleTimeProcessorTest {
PopBufferMergeService popBufferMergeService = mock(PopBufferMergeService.class);
when(brokerController.getPopMessageProcessor()).thenReturn(popMessageProcessor);
when(popMessageProcessor.getPopBufferMergeService()).thenReturn(popBufferMergeService);
+
+ ConsumerData consumerData = createConsumerData(group, topic);
+ clientInfo = new ClientChannelInfo(channel, "127.0.0.1", LanguageCode.JAVA, 0);
+ brokerController.getConsumerManager().registerConsumer(
+ consumerData.getGroupName(),
+ clientInfo,
+ consumerData.getConsumeType(),
+ consumerData.getMessageModel(),
+ consumerData.getConsumeFromWhere(),
+ consumerData.getSubscriptionDataSet(),
+ false);
clientInfo = new ClientChannelInfo(channel, "127.0.0.1", LanguageCode.JAVA, 0);
changeInvisibleTimeProcessor = new ChangeInvisibleTimeProcessor(brokerController);
@@ -177,4 +196,58 @@ public class ChangeInvisibleTimeProcessorTest {
assertThat(responseToReturn.getCode()).isEqualTo(ResponseCode.NO_MESSAGE);
assertThat(responseToReturn.getOpaque()).isEqualTo(request.getOpaque());
}
+
+ @Test
+ public void testProcessRequestAsync_JsonParsing() throws Exception {
+ Channel mockChannel = mock(Channel.class);
+ RemotingCommand mockRequest = mock(RemotingCommand.class);
+ BrokerController mockBrokerController = mock(BrokerController.class);
+ TopicConfigManager mockTopicConfigManager = mock(TopicConfigManager.class);
+ MessageStore mockMessageStore = mock(MessageStore.class);
+ BrokerConfig mockBrokerConfig = mock(BrokerConfig.class);
+ BrokerStatsManager mockBrokerStatsManager = mock(BrokerStatsManager.class);
+ PopMessageProcessor mockPopMessageProcessor = mock(PopMessageProcessor.class);
+ PopBufferMergeService mockPopBufferMergeService = mock(PopBufferMergeService.class);
+ BrokerMetricsManager brokerMetricsManager = mock(BrokerMetricsManager.class);
+ PopMetricsManager popMetricsManager = mock(PopMetricsManager.class);
+
+ when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+ when(mockBrokerController.getBrokerMetricsManager()).thenReturn(brokerMetricsManager);
+ doNothing().when(popMetricsManager).incPopReviveCkPutCount(any(), any());
+ when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+ when(mockBrokerController.getTopicConfigManager()).thenReturn(mockTopicConfigManager);
+ when(mockBrokerController.getMessageStore()).thenReturn(mockMessageStore);
+ when(mockBrokerController.getBrokerConfig()).thenReturn(mockBrokerConfig);
+ when(mockBrokerController.getBrokerStatsManager()).thenReturn(mockBrokerStatsManager);
+ when(mockBrokerController.getPopMessageProcessor()).thenReturn(mockPopMessageProcessor);
+ when(mockPopMessageProcessor.getPopBufferMergeService()).thenReturn(mockPopBufferMergeService);
+ when(mockPopBufferMergeService.addAk(anyInt(), any())).thenReturn(false);
+ when(mockBrokerController.getEscapeBridge()).thenReturn(escapeBridge);
+ PutMessageResult mockPutMessageResult = new PutMessageResult(PutMessageStatus.PUT_OK, null, true);
+ when(mockBrokerController.getEscapeBridge().asyncPutMessageToSpecificQueue(any()))
+ .thenReturn(CompletableFuture.completedFuture(mockPutMessageResult));
+
+ TopicConfig topicConfig = new TopicConfig();
+ topicConfig.setReadQueueNums(4);
+ when(mockTopicConfigManager.selectTopicConfig(anyString())).thenReturn(topicConfig);
+ when(mockMessageStore.getMinOffsetInQueue(anyString(), anyInt())).thenReturn(0L);
+ when(mockMessageStore.getMaxOffsetInQueue(anyString(), anyInt())).thenReturn(10L);
+ when(mockBrokerConfig.isPopConsumerKVServiceEnable()).thenReturn(false);
+
+ ChangeInvisibleTimeRequestHeader requestHeader = new ChangeInvisibleTimeRequestHeader();
+ requestHeader.setTopic("TestTopic");
+ requestHeader.setQueueId(1);
+ requestHeader.setOffset(5L);
+ requestHeader.setConsumerGroup("TestGroup");
+ requestHeader.setExtraInfo("0 10000 10000 0 TestBroker 1");
+ requestHeader.setInvisibleTime(60000L);
+ when(mockRequest.decodeCommandCustomHeader(ChangeInvisibleTimeRequestHeader.class)).thenReturn(requestHeader);
+
+ ChangeInvisibleTimeProcessor processor = new ChangeInvisibleTimeProcessor(mockBrokerController);
+ CompletableFuture<RemotingCommand> futureResponse = processor.processRequestAsync(mockChannel, mockRequest, true);
+
+ RemotingCommand response = futureResponse.get();
+ assertNotNull(response);
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+ }
}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java
index acc7a3da74..6cbbd9cfd9 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java
@@ -16,19 +16,22 @@
*/
package org.apache.rocketmq.broker.processor;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandlerContext;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.rocketmq.broker.BrokerController;
-import org.apache.rocketmq.broker.client.ClientChannelInfo;
+import org.apache.rocketmq.broker.client.ConsumerManager;
+import org.apache.rocketmq.broker.failover.EscapeBridge;
+import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
+import org.apache.rocketmq.broker.metrics.PopMetricsManager;
import org.apache.rocketmq.broker.schedule.ScheduleMessageService;
+import org.apache.rocketmq.broker.topic.TopicConfigManager;
import org.apache.rocketmq.common.BrokerConfig;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
-import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumerData;
+import org.apache.rocketmq.common.message.MessageExtBrokerInner;
import org.apache.rocketmq.store.DefaultMessageStore;
+import org.apache.rocketmq.store.PutMessageResult;
+import org.apache.rocketmq.store.PutMessageStatus;
import org.apache.rocketmq.store.config.MessageStoreConfig;
import org.apache.rocketmq.store.pop.AckMsg;
import org.apache.rocketmq.store.pop.PopCheckPoint;
@@ -37,56 +40,83 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
-import static org.apache.rocketmq.broker.processor.PullMessageProcessorTest.createConsumerData;
+import java.lang.reflect.Method;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
public class PopBufferMergeServiceTest {
- @Spy
- private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(), new NettyClientConfig(), new MessageStoreConfig());
+
@Mock
+ private BrokerController brokerController;
+
private PopMessageProcessor popMessageProcessor;
+
+ @Mock
+ private ScheduleMessageService scheduleMessageService;
+
@Mock
- private ChannelHandlerContext handlerContext;
+ private TopicConfigManager topicConfigManager;
+
+ @Mock
+ private ConsumerManager consumerManager;
+
@Mock
private DefaultMessageStore messageStore;
- private ScheduleMessageService scheduleMessageService;
- private ClientChannelInfo clientChannelInfo;
- private String group = "FooBarGroup";
- private String topic = "FooBar";
+
+ @Mock
+ private MessageStoreConfig messageStoreConfig;
+
+ private String defaultGroup = "defaultGroup";
+
+ private String defaultTopic = "defaultTopic";
+
+ private PopBufferMergeService popBufferMergeService;
+
+ @Mock
+ private BrokerConfig brokerConfig;
+
+ @Mock
+ private EscapeBridge escapeBridge;
@Before
public void init() throws Exception {
- FieldUtils.writeField(brokerController.getBrokerConfig(), "enablePopBufferMerge", true, true);
- brokerController.setMessageStore(messageStore);
+ when(brokerConfig.getBrokerIP1()).thenReturn("127.0.0.1");
+ when(brokerConfig.isEnablePopBufferMerge()).thenReturn(true);
+ when(brokerConfig.getPopCkStayBufferTime()).thenReturn(10 * 1000);
+ when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+ when(brokerController.getEscapeBridge()).thenReturn(escapeBridge);
+ when(brokerController.getMessageStore()).thenReturn(messageStore);
+ when(brokerController.getTopicConfigManager()).thenReturn(topicConfigManager);
+ when(brokerController.getScheduleMessageService()).thenReturn(scheduleMessageService);
+ when(brokerController.getConsumerManager()).thenReturn(consumerManager);
+ when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
popMessageProcessor = new PopMessageProcessor(brokerController);
- scheduleMessageService = new ScheduleMessageService(brokerController);
- scheduleMessageService.parseDelayLevel();
- Channel mockChannel = mock(Channel.class);
- brokerController.getTopicConfigManager().getTopicConfigTable().put(topic, new TopicConfig());
- clientChannelInfo = new ClientChannelInfo(mockChannel);
- ConsumerData consumerData = createConsumerData(group, topic);
- brokerController.getConsumerManager().registerConsumer(
- consumerData.getGroupName(),
- clientChannelInfo,
- consumerData.getConsumeType(),
- consumerData.getMessageModel(),
- consumerData.getConsumeFromWhere(),
- consumerData.getSubscriptionDataSet(),
- false);
+ popBufferMergeService = new PopBufferMergeService(brokerController, popMessageProcessor);
+ FieldUtils.writeDeclaredField(popBufferMergeService, "brokerController", brokerController, true);
+ ConcurrentMap<String, TopicConfig> topicConfigTable = new ConcurrentHashMap<>();
+ topicConfigTable.put(defaultTopic, new TopicConfig());
+ when(topicConfigManager.getTopicConfigTable()).thenReturn(topicConfigTable);
}
- @Test(timeout = 10_000)
+ @Test(timeout = 15_000)
public void testBasic() throws Exception {
// This test case fails on Windows in CI pipeline
// Disable it for later fix
Assume.assumeFalse(MixAll.isWindows());
- PopBufferMergeService popBufferMergeService = new PopBufferMergeService(brokerController, popMessageProcessor);
- popBufferMergeService.start();
PopCheckPoint ck = new PopCheckPoint();
ck.setBitMap(0);
int msgCnt = 1;
@@ -97,8 +127,8 @@ public class PopBufferMergeServiceTest {
ck.setInvisibleTime(invisibleTime);
int offset = 100;
ck.setStartOffset(offset);
- ck.setCId(group);
- ck.setTopic(topic);
+ ck.setCId(defaultGroup);
+ ck.setTopic(defaultTopic);
int queueId = 0;
ck.setQueueId(queueId);
@@ -108,18 +138,100 @@ public class PopBufferMergeServiceTest {
AckMsg ackMsg = new AckMsg();
ackMsg.setAckOffset(ackOffset);
ackMsg.setStartOffset(offset);
- ackMsg.setConsumerGroup(group);
- ackMsg.setTopic(topic);
+ ackMsg.setConsumerGroup(defaultGroup);
+ ackMsg.setTopic(defaultTopic);
ackMsg.setQueueId(queueId);
ackMsg.setPopTime(popTime);
try {
assertThat(popBufferMergeService.addCk(ck, reviveQid, ackOffset, nextBeginOffset)).isTrue();
- assertThat(popBufferMergeService.getLatestOffset(topic, group, queueId)).isEqualTo(nextBeginOffset);
+ assertThat(popBufferMergeService.getLatestOffset(defaultTopic, defaultGroup, queueId)).isEqualTo(nextBeginOffset);
Thread.sleep(1000); // wait background threads of PopBufferMergeService run for some time
assertThat(popBufferMergeService.addAk(reviveQid, ackMsg)).isTrue();
- assertThat(popBufferMergeService.getLatestOffset(topic, group, queueId)).isEqualTo(nextBeginOffset);
+ assertThat(popBufferMergeService.getLatestOffset(defaultTopic, defaultGroup, queueId)).isEqualTo(nextBeginOffset);
} finally {
popBufferMergeService.shutdown(true);
}
}
+
+ @Test
+ public void testAddCkJustOffset_MergeKeyConflict() {
+ PopCheckPoint point = mock(PopCheckPoint.class);
+ String mergeKey = "testMergeKey";
+ when(point.getTopic()).thenReturn(mergeKey);
+ when(point.getCId()).thenReturn("");
+ when(point.getQueueId()).thenReturn(0);
+ when(point.getStartOffset()).thenReturn(0L);
+ when(point.getPopTime()).thenReturn(0L);
+ when(point.getBrokerName()).thenReturn("");
+ popBufferMergeService.buffer.put(mergeKey + "000", mock(PopBufferMergeService.PopCheckPointWrapper.class));
+
+ assertFalse(popBufferMergeService.addCkJustOffset(point, 0, 0, 0));
+ }
+
+ @Test
+ public void testAddCkMock() {
+ int queueId = 0;
+ long startOffset = 100L;
+ long invisibleTime = 30_000L;
+ long popTime = System.currentTimeMillis();
+ int reviveQueueId = 0;
+ long nextBeginOffset = 101L;
+ String brokerName = "brokerName";
+ popBufferMergeService.addCkMock(defaultGroup, defaultTopic, queueId, startOffset, invisibleTime, popTime, reviveQueueId, nextBeginOffset, brokerName);
+ verify(brokerConfig, times(1)).isEnablePopLog();
+ }
+
+ @Test
+ public void testPutAckToStore() throws Exception {
+ PopCheckPoint point = new PopCheckPoint();
+ point.setStartOffset(100L);
+ point.setCId("testGroup");
+ point.setTopic("testTopic");
+ point.setQueueId(1);
+ point.setPopTime(System.currentTimeMillis());
+ point.setBrokerName("testBroker");
+
+ PopBufferMergeService.PopCheckPointWrapper pointWrapper = mock(PopBufferMergeService.PopCheckPointWrapper.class);
+ when(pointWrapper.getCk()).thenReturn(point);
+ when(pointWrapper.getReviveQueueId()).thenReturn(0);
+
+ AtomicInteger toStoreBits = new AtomicInteger(0);
+ when(pointWrapper.getToStoreBits()).thenReturn(toStoreBits);
+
+ byte msgIndex = 0;
+ AtomicInteger count = new AtomicInteger(0);
+
+ EscapeBridge escapeBridge = mock(EscapeBridge.class);
+ when(brokerController.getEscapeBridge()).thenReturn(escapeBridge);
+ when(brokerController.getBrokerConfig().isAppendAckAsync()).thenReturn(false);
+ BrokerMetricsManager brokerMetricsManager = mock(BrokerMetricsManager.class);
+ PopMetricsManager popMetricsManager = mock(PopMetricsManager.class);
+
+ when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+ when(brokerController.getBrokerMetricsManager()).thenReturn(brokerMetricsManager);
+ doNothing().when(popMetricsManager).incPopReviveCkPutCount(any(), any());
+ when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+
+ when(escapeBridge.putMessageToSpecificQueue(any())).thenAnswer(invocation -> {
+ MessageExtBrokerInner capturedMessage = invocation.getArgument(0);
+ AckMsg ackMsg = JSON.parseObject(capturedMessage.getBody(), AckMsg.class);
+
+ assertEquals(point.ackOffsetByIndex(msgIndex), ackMsg.getAckOffset());
+ assertEquals(point.getStartOffset(), ackMsg.getStartOffset());
+ assertEquals(point.getCId(), ackMsg.getConsumerGroup());
+ assertEquals(point.getTopic(), ackMsg.getTopic());
+ assertEquals(point.getQueueId(), ackMsg.getQueueId());
+ assertEquals(point.getPopTime(), ackMsg.getPopTime());
+ assertEquals(point.getBrokerName(), ackMsg.getBrokerName());
+
+ PutMessageResult result = mock(PutMessageResult.class);
+ when(result.getPutMessageStatus()).thenReturn(PutMessageStatus.PUT_OK);
+ return result;
+ });
+
+ Method method = PopBufferMergeService.class.getDeclaredMethod("putAckToStore", PopBufferMergeService.PopCheckPointWrapper.class, byte.class, AtomicInteger.class);
+ method.setAccessible(true);
+ method.invoke(popBufferMergeService, pointWrapper, msgIndex, count);
+ verify(escapeBridge, times(1)).putMessageToSpecificQueue(any(MessageExtBrokerInner.class));
+ }
}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java
index 59559d3cfd..5d7b97f229 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java
@@ -16,10 +16,9 @@
*/
package org.apache.rocketmq.broker.processor;
+import com.alibaba.fastjson2.JSON;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedChannel;
-import java.nio.ByteBuffer;
-import java.util.concurrent.CompletableFuture;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
@@ -28,6 +27,7 @@ import org.apache.rocketmq.common.KeyBuilder;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.constant.ConsumeInitMode;
import org.apache.rocketmq.common.message.MessageDecoder;
+import org.apache.rocketmq.common.message.MessageExtBrokerInner;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.netty.NettyClientConfig;
import org.apache.rocketmq.remoting.netty.NettyServerConfig;
@@ -43,7 +43,7 @@ import org.apache.rocketmq.store.SelectMappedBufferResult;
import org.apache.rocketmq.store.config.MessageStoreConfig;
import org.apache.rocketmq.store.exception.ConsumeQueueException;
import org.apache.rocketmq.store.logfile.DefaultMappedFile;
-import org.junit.Assert;
+import org.apache.rocketmq.store.pop.PopCheckPoint;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,8 +51,13 @@ import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CompletableFuture;
+
import static org.apache.rocketmq.broker.processor.PullMessageProcessorTest.createConsumerData;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -171,17 +176,17 @@ public class PopMessageProcessorTest {
.thenReturn(CompletableFuture.completedFuture(getMessageResult));
long offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, retryTopic, 0);
- Assert.assertEquals(-1, offset);
+ assertEquals(-1, offset);
RemotingCommand request = createPopMsgCommand(newGroup, topic, 0, ConsumeInitMode.MAX);
popMessageProcessor.processRequest(handlerContext, request);
offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, retryTopic, 0);
- Assert.assertEquals(minOffset, offset);
+ assertEquals(minOffset, offset);
when(messageStore.getMinOffsetInQueue(retryTopic, 0)).thenReturn(minOffset * 2);
popMessageProcessor.processRequest(handlerContext, request);
offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, retryTopic, 0);
- Assert.assertEquals(minOffset, offset); // will not entry getInitOffset() again
+ assertEquals(minOffset, offset); // will not entry getInitOffset() again
messageStore.getMinOffsetInQueue(retryTopic, 0); // prevent UnnecessaryStubbingException
}
@@ -196,20 +201,47 @@ public class PopMessageProcessorTest {
.thenReturn(CompletableFuture.completedFuture(getMessageResult));
long offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, topic, 0);
- Assert.assertEquals(-1, offset);
+ assertEquals(-1, offset);
RemotingCommand request = createPopMsgCommand(newGroup, topic, 0, ConsumeInitMode.MAX);
popMessageProcessor.processRequest(handlerContext, request);
offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, topic, 0);
- Assert.assertEquals(maxOffset - 1, offset); // checkInMem return false
+ assertEquals(maxOffset - 1, offset); // checkInMem return false
when(messageStore.getMaxOffsetInQueue(topic, 0)).thenReturn(maxOffset * 2);
popMessageProcessor.processRequest(handlerContext, request);
offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, topic, 0);
- Assert.assertEquals(maxOffset - 1, offset); // will not entry getInitOffset() again
+ assertEquals(maxOffset - 1, offset); // will not entry getInitOffset() again
messageStore.getMaxOffsetInQueue(topic, 0); // prevent UnnecessaryStubbingException
}
+ @Test
+ public void testBuildCkMsgJsonParsing() {
+ PopCheckPoint ck = new PopCheckPoint();
+ ck.setTopic("TestTopic");
+ ck.setQueueId(1);
+ ck.setStartOffset(100L);
+ ck.setCId("TestConsumer");
+ ck.setPopTime(System.currentTimeMillis());
+ ck.setBrokerName("TestBroker");
+
+ int reviveQid = 0;
+ PopMessageProcessor processor = new PopMessageProcessor(brokerController);
+
+ MessageExtBrokerInner result = processor.buildCkMsg(ck, reviveQid);
+
+ String jsonBody = new String(result.getBody(), StandardCharsets.UTF_8);
+ PopCheckPoint actual = JSON.parseObject(jsonBody, PopCheckPoint.class);
+
+ assertEquals(ck.getTopic(), actual.getTopic());
+ assertEquals(ck.getQueueId(), actual.getQueueId());
+ assertEquals(ck.getStartOffset(), actual.getStartOffset());
+ assertEquals(ck.getCId(), actual.getCId());
+ assertEquals(ck.getPopTime(), actual.getPopTime());
+ assertEquals(ck.getBrokerName(), actual.getBrokerName());
+ assertEquals(ck.getReviveTime(), actual.getReviveTime());
+ }
+
private RemotingCommand createPopMsgCommand() {
return createPopMsgCommand(group, topic, -1, ConsumeInitMode.MAX);
}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
index 6e77e7c557..fa7e9982e1 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
@@ -16,13 +16,7 @@
*/
package org.apache.rocketmq.broker.processor;
-import com.alibaba.fastjson.JSON;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.failover.EscapeBridge;
@@ -42,12 +36,13 @@ import org.apache.rocketmq.common.message.MessageExtBrokerInner;
import org.apache.rocketmq.common.utils.DataConverter;
import org.apache.rocketmq.common.utils.NetworkUtil;
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.store.AppendMessageResult;
+import org.apache.rocketmq.store.AppendMessageStatus;
import org.apache.rocketmq.store.MessageStore;
import org.apache.rocketmq.store.PutMessageResult;
import org.apache.rocketmq.store.PutMessageStatus;
-import org.apache.rocketmq.store.AppendMessageResult;
-import org.apache.rocketmq.store.AppendMessageStatus;
import org.apache.rocketmq.store.pop.AckMsg;
+import org.apache.rocketmq.store.pop.BatchAckMsg;
import org.apache.rocketmq.store.pop.PopCheckPoint;
import org.apache.rocketmq.store.timer.TimerMessageStore;
import org.junit.Assert;
@@ -58,18 +53,27 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.any;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
public class PopReviveServiceTest {
@@ -139,7 +143,7 @@ public class PopReviveServiceTest {
long maxReviveOffset = 4;
when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID))
- .thenReturn(0L);
+ .thenReturn(0L);
List<MessageExt> reviveMessageExtList = new ArrayList<>();
long basePopTime = System.currentTimeMillis();
{
@@ -176,7 +180,7 @@ public class PopReviveServiceTest {
long maxReviveOffset = 4;
when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID))
- .thenReturn(0L);
+ .thenReturn(0L);
List<MessageExt> reviveMessageExtList = new ArrayList<>();
long basePopTime = System.currentTimeMillis() - brokerConfig.getReviveAckWaitMs() * 2;
{
@@ -213,7 +217,7 @@ public class PopReviveServiceTest {
long maxReviveOffset = 4;
when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID))
- .thenReturn(0L);
+ .thenReturn(0L);
List<MessageExt> reviveMessageExtList = new ArrayList<>();
long basePopTime = System.currentTimeMillis() - brokerConfig.getReviveAckWaitMs() * 2;
{
@@ -419,6 +423,59 @@ public class PopReviveServiceTest {
verify(messageStore, times(1)).putMessage(any(MessageExtBrokerInner.class)); // rewrite CK
}
+ @Test
+ public void testReviveMsgFromBatchAck() throws Throwable {
+ brokerConfig.setEnableSkipLongAwaitingAck(true);
+ when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID)).thenReturn(0L);
+ List<MessageExt> reviveMessageExtList = new ArrayList<>();
+ long basePopTime = System.currentTimeMillis();
+ reviveMessageExtList.add(buildBatchAckMsg(buildBatchAckMsg(Arrays.asList(1L, 2L, 3L), basePopTime), 1, 1, basePopTime));
+ doReturn(reviveMessageExtList, new ArrayList<>()).when(popReviveService).getReviveMessage(anyLong(), anyInt());
+
+ PopReviveService.ConsumeReviveObj consumeReviveObj = new PopReviveService.ConsumeReviveObj();
+ popReviveService.consumeReviveMessage(consumeReviveObj);
+ assertEquals(1, consumeReviveObj.map.size());
+
+ ArgumentCaptor<Long> commitOffsetCaptor = ArgumentCaptor.forClass(Long.class);
+ doNothing().when(consumerOffsetManager).commitOffset(anyString(), anyString(), anyString(), anyInt(), commitOffsetCaptor.capture());
+ popReviveService.mergeAndRevive(consumeReviveObj);
+ assertEquals(1, commitOffsetCaptor.getValue().longValue());
+ }
+
+ public static MessageExtBrokerInner buildBatchAckMsg(BatchAckMsg batchAckMsg, long deliverMs, long reviveOffset, long deliverTime) {
+ MessageExtBrokerInner result = buildBatchAckInnerMessage(REVIVE_TOPIC, batchAckMsg, REVIVE_QUEUE_ID, STORE_HOST, deliverMs, PopMessageProcessor.genAckUniqueId(batchAckMsg));
+ result.setQueueOffset(reviveOffset);
+ result.setDeliverTimeMs(deliverMs);
+ result.setStoreTimestamp(deliverTime);
+ return result;
+ }
+
+ public static BatchAckMsg buildBatchAckMsg(Collection<Long> offsets, long popTime) {
+ BatchAckMsg result = new BatchAckMsg();
+ result.setConsumerGroup(GROUP);
+ result.setTopic(TOPIC);
+ result.setQueueId(0);
+ result.setPopTime(popTime);
+ result.setBrokerName("broker-a");
+ result.getAckOffsetList().addAll(offsets);
+ return result;
+ }
+
+ public static MessageExtBrokerInner buildBatchAckInnerMessage(String reviveTopic, AckMsg ackMsg, int reviveQid, SocketAddress host, long deliverMs, String ackUniqueId) {
+ MessageExtBrokerInner result = new MessageExtBrokerInner();
+ result.setTopic(reviveTopic);
+ result.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
+ result.setQueueId(reviveQid);
+ result.setTags(PopAckConstants.BATCH_ACK_TAG);
+ result.setBornTimestamp(System.currentTimeMillis());
+ result.setBornHost(host);
+ result.setStoreHost(host);
+ result.setDeliverTimeMs(deliverMs);
+ result.getProperties().put(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, ackUniqueId);
+ result.setPropertiesString(MessageDecoder.messageProperties2String(result.getProperties()));
+ return result;
+ }
+
public static PopCheckPoint buildPopCheckPoint(long startOffset, long popTime, long reviveOffset) {
PopCheckPoint ck = new PopCheckPoint();
ck.setStartOffset(startOffset);
@@ -467,14 +524,14 @@ public class PopReviveServiceTest {
}
public static MessageExtBrokerInner buildAckMsg(AckMsg ackMsg, long deliverMs, long reviveOffset,
- long deliverTime) {
+ long deliverTime) {
MessageExtBrokerInner messageExtBrokerInner = buildAckInnerMessage(
- REVIVE_TOPIC,
- ackMsg,
- REVIVE_QUEUE_ID,
- STORE_HOST,
- deliverMs,
- PopMessageProcessor.genAckUniqueId(ackMsg)
+ REVIVE_TOPIC,
+ ackMsg,
+ REVIVE_QUEUE_ID,
+ STORE_HOST,
+ deliverMs,
+ PopMessageProcessor.genAckUniqueId(ackMsg)
);
messageExtBrokerInner.setQueueOffset(reviveOffset);
messageExtBrokerInner.setDeliverTimeMs(deliverMs);
@@ -483,7 +540,7 @@ public class PopReviveServiceTest {
}
public static MessageExtBrokerInner buildAckInnerMessage(String reviveTopic, AckMsg ackMsg, int reviveQid,
- SocketAddress host, long deliverMs, String ackUniqueId) {
+ SocketAddress host, long deliverMs, String ackUniqueId) {
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(reviveTopic);
msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java
index 3c975a599b..bc34e26bf5 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java
@@ -47,7 +47,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
@@ -101,13 +100,13 @@ public class SubscriptionGroupManagerTest {
subscriptionGroupConfig.setGroupName(group);
Map<String, String> attr = ImmutableMap.of("+test", "true");
subscriptionGroupConfig.setAttributes(attr);
+ SubscriptionGroupManager subscriptionGroupManager = new SubscriptionGroupManager(brokerControllerMock);
subscriptionGroupManager.updateSubscriptionGroupConfig(subscriptionGroupConfig);
SubscriptionGroupConfig result = subscriptionGroupManager.getSubscriptionGroupTable().get(group);
assertThat(result).isNotNull();
assertThat(result.getGroupName()).isEqualTo(group);
assertThat(result.getAttributes().get("test")).isEqualTo("true");
-
SubscriptionGroupConfig subscriptionGroupConfig1 = new SubscriptionGroupConfig();
subscriptionGroupConfig1.setGroupName(group);
Map<String, String> attrRemove = ImmutableMap.of("-test", "");
@@ -157,14 +156,11 @@ public class SubscriptionGroupManagerTest {
groupNames.add(groupName);
}
+ SubscriptionGroupManager subscriptionGroupManager = new SubscriptionGroupManager(brokerControllerMock);
subscriptionGroupManager.updateSubscriptionGroupConfigList(configList);
- // Verifying that persist() is called once
- verify(subscriptionGroupManager, times(1)).persist();
-
groupNames.forEach(groupName ->
assertThat(subscriptionGroupManager.getSubscriptionGroupTable().get(groupName)).isNotNull());
-
}
@Test
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java
index b74e57ab93..9b25e0134c 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java
@@ -17,15 +17,11 @@
package org.apache.rocketmq.broker.topic;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.remoting.protocol.body.TopicQueueMappingSerializeWrapper;
import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingDetail;
import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingUtils;
import org.apache.rocketmq.remoting.protocol.statictopic.TopicRemappingDetailWrapper;
@@ -37,6 +33,16 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
@@ -79,9 +85,9 @@ public class TopicQueueMappingManagerTest {
String topic = UUID.randomUUID().toString();
int queueNum = 10;
TopicRemappingDetailWrapper topicRemappingDetailWrapper = TopicQueueMappingUtils.createTopicConfigMapping(topic, queueNum, brokers, new HashMap<>());
- Assert.assertEquals(1, topicRemappingDetailWrapper.getBrokerConfigMap().size());
+ assertEquals(1, topicRemappingDetailWrapper.getBrokerConfigMap().size());
TopicQueueMappingDetail topicQueueMappingDetail = topicRemappingDetailWrapper.getBrokerConfigMap().values().iterator().next().getMappingDetail();
- Assert.assertEquals(queueNum, topicQueueMappingDetail.getHostedQueues().size());
+ assertEquals(queueNum, topicQueueMappingDetail.getHostedQueues().size());
mappingDetailMap.put(topic, topicQueueMappingDetail);
}
}
@@ -89,7 +95,7 @@ public class TopicQueueMappingManagerTest {
{
topicQueueMappingManager = new TopicQueueMappingManager(brokerController);
Assert.assertTrue(topicQueueMappingManager.load());
- Assert.assertEquals(0, topicQueueMappingManager.getTopicQueueMappingTable().size());
+ assertEquals(0, topicQueueMappingManager.getTopicQueueMappingTable().size());
for (TopicQueueMappingDetail mappingDetail : mappingDetailMap.values()) {
for (int i = 0; i < 10; i++) {
topicQueueMappingManager.updateTopicQueueMapping(mappingDetail, false, false, true);
@@ -101,11 +107,49 @@ public class TopicQueueMappingManagerTest {
{
topicQueueMappingManager = new TopicQueueMappingManager(brokerController);
Assert.assertTrue(topicQueueMappingManager.load());
- Assert.assertEquals(mappingDetailMap.size(), topicQueueMappingManager.getTopicQueueMappingTable().size());
+ assertEquals(mappingDetailMap.size(), topicQueueMappingManager.getTopicQueueMappingTable().size());
for (TopicQueueMappingDetail topicQueueMappingDetail: topicQueueMappingManager.getTopicQueueMappingTable().values()) {
- Assert.assertEquals(topicQueueMappingDetail, mappingDetailMap.get(topicQueueMappingDetail.getTopic()));
+ assertEquals(topicQueueMappingDetail, mappingDetailMap.get(topicQueueMappingDetail.getTopic()));
}
}
delete(topicQueueMappingManager);
}
+
+ @Test
+ public void testEncodePretty() {
+ TopicQueueMappingManager topicQueueMappingManager = new TopicQueueMappingManager(null);
+ TopicQueueMappingDetail detail = new TopicQueueMappingDetail();
+ detail.setTopic("testTopic");
+ detail.setBname("testBroker");
+
+ topicQueueMappingManager.getTopicQueueMappingTable().put("testTopic", detail);
+ topicQueueMappingManager.getDataVersion().nextVersion();
+
+ String actual = topicQueueMappingManager.encode(true);
+ TopicQueueMappingSerializeWrapper expectedWrapper = new TopicQueueMappingSerializeWrapper();
+ expectedWrapper.setTopicQueueMappingInfoMap(new ConcurrentHashMap<>(topicQueueMappingManager.getTopicQueueMappingTable()));
+ expectedWrapper.setDataVersion(topicQueueMappingManager.getDataVersion());
+ String expected = JSON.toJSONString(expectedWrapper, JSONWriter.Feature.PrettyFormat);
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testEncodeNonPretty() {
+ TopicQueueMappingManager topicQueueMappingManager = new TopicQueueMappingManager(null);
+ TopicQueueMappingDetail detail = new TopicQueueMappingDetail();
+ detail.setTopic("testTopic");
+ detail.setBname("testBroker");
+
+ topicQueueMappingManager.getTopicQueueMappingTable().put("testTopic", detail);
+ topicQueueMappingManager.getDataVersion().nextVersion();
+
+ String actual = topicQueueMappingManager.encode(false);
+ TopicQueueMappingSerializeWrapper expectedWrapper = new TopicQueueMappingSerializeWrapper();
+ expectedWrapper.setTopicQueueMappingInfoMap(new ConcurrentHashMap<>(topicQueueMappingManager.getTopicQueueMappingTable()));
+ expectedWrapper.setDataVersion(topicQueueMappingManager.getDataVersion());
+ String expected = JSON.toJSONString(expectedWrapper);
+
+ assertEquals(expected, actual);
+ }
}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java
index 690b4eabb5..62a6ad8b5b 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java
@@ -19,23 +19,40 @@ package org.apache.rocketmq.broker.transaction.queue;
import org.apache.rocketmq.broker.transaction.TransactionMetrics;
import org.apache.rocketmq.broker.transaction.TransactionMetrics.Metric;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Collections;
+import java.util.UUID;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class TransactionMetricsTest {
private TransactionMetrics transactionMetrics;
private String configPath;
+ private Path path;
@Before
- public void setUp() throws Exception {
- configPath = "configPath";
- transactionMetrics = new TransactionMetrics(configPath);
+ public void before() throws Exception {
+ configPath = createBaseDir();
+ path = Paths.get(configPath);
+ transactionMetrics = spy(new TransactionMetrics(configPath));
+ }
+
+ @After
+ public void after() throws Exception {
+ deleteFile(configPath);
+ assertFalse(path.toFile().exists());
}
/**
@@ -80,4 +97,40 @@ public class TransactionMetricsTest {
transactionMetrics.cleanMetrics(Collections.singleton(topic));
assert transactionMetrics.getTransactionCount(topic) == 0;
}
+
+ @Test
+ public void testPersist() {
+ assertFalse(path.toFile().exists());
+ transactionMetrics.persist();
+ assertTrue(path.toFile().exists());
+ verify(transactionMetrics).persist();
+ }
+
+ private String createBaseDir() {
+ String baseDir = System.getProperty("java.io.tmpdir") + File.separator + "unitteststore-" + UUID.randomUUID();
+ final File file = new File(baseDir);
+ if (file.exists()) {
+ System.exit(1);
+ }
+ return baseDir;
+ }
+
+ private void deleteFile(String fileName) {
+ deleteFile(new File(fileName));
+ }
+
+ private 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();
+ }
+ }
}
diff --git a/client/BUILD.bazel b/client/BUILD.bazel
index 31681f1029..3bd84606a2 100644
--- a/client/BUILD.bazel
+++ b/client/BUILD.bazel
@@ -27,7 +27,6 @@ java_library(
"@maven//:commons_validator_commons_validator",
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:io_netty_netty_all",
"@maven//:io_opentracing_opentracing_api",
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index 95bb0e8a96..11af6ecd4b 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.client.impl;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.ClientConfig;
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index 3055f2cdee..bb838a6265 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -16,26 +16,8 @@
*/
package org.apache.rocketmq.client.impl.factory;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import io.netty.channel.Channel;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.admin.MQAdminExtInner;
@@ -86,6 +68,25 @@ import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.remoting.protocol.route.QueueData;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
import static org.apache.rocketmq.remoting.rpc.ClientMetadata.topicRouteData2EndpointsForStaticTopic;
public class MQClientInstance {
diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java b/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java
index d160eb4eae..5405275398 100644
--- a/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java
+++ b/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.client.producer;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import org.apache.rocketmq.common.message.MessageQueue;
public class SendResult {
diff --git a/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java b/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java
index 592c247057..f57b3f80fe 100644
--- a/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java
@@ -17,17 +17,6 @@
package org.apache.rocketmq.client.consumer;
-import java.io.ByteArrayOutputStream;
-import java.lang.reflect.Field;
-import java.net.InetSocketAddress;
-import java.time.Duration;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.consumer.store.OffsetStore;
@@ -65,6 +54,18 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Field;
+import java.net.InetSocketAddress;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown;
import static org.awaitility.Awaitility.await;
@@ -75,6 +76,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -898,5 +900,6 @@ public class DefaultLitePullConsumerTest {
ConcurrentMap<String, MQClientInstance> factoryTable = (ConcurrentMap<String, MQClientInstance>) FieldUtils.readDeclaredField(MQClientManager.getInstance(), "factoryTable", true);
factoryTable.put(litePullConsumer.buildMQClientId(), mQClientFactory);
doReturn(false).when(mQClientFactory).updateTopicRouteInfoFromNameServer(anyString());
+ doNothing().when(mQClientFactory).updateTopicRouteInfoFromNameServer();
}
}
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
index c12b23cb0d..c8d23274bd 100644
--- a/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.client.impl;
+import com.alibaba.fastjson2.JSON;
import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.consumer.AckCallback;
import org.apache.rocketmq.client.consumer.AckResult;
@@ -34,6 +35,7 @@ import org.apache.rocketmq.client.producer.DefaultMQProducer;
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.CheckRocksdbCqWriteResult;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.ObjectCreator;
import org.apache.rocketmq.common.Pair;
@@ -2031,6 +2033,22 @@ public class MQClientAPIImplTest {
}
}
+ @Test
+ public void testCheckRocksdbCqWriteProgress() throws Exception {
+ RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success");
+ CheckRocksdbCqWriteResult expectedResult = new CheckRocksdbCqWriteResult();
+ expectedResult.setCheckStatus(CheckRocksdbCqWriteResult.CheckStatus.CHECK_OK.getValue());
+ response.setBody(JSON.toJSONString(expectedResult).getBytes());
+
+ when(remotingClient.invokeSync(any(String.class), any(RemotingCommand.class), any(Long.class)))
+ .thenReturn(response);
+
+ CheckRocksdbCqWriteResult result = mqClientAPI.checkRocksdbCqWriteProgress(
+ "brokerAddr", "testTopic", 12345L, 3000L);
+
+ assertEquals(CheckRocksdbCqWriteResult.CheckStatus.CHECK_OK.getValue(), result.getCheckStatus());
+ }
+
private Properties createProperties() {
Properties result = new Properties();
result.put("key", "value");
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java
index 71682fb52c..520f4da5f2 100644
--- a/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java
@@ -206,7 +206,7 @@ public class MqClientAdminImplTest {
@Test
public void assertUpdateOrCreateSubscriptionGroupWithSuccess() throws Exception {
setResponseSuccess(null);
- SubscriptionGroupConfig config = mock(SubscriptionGroupConfig.class);
+ SubscriptionGroupConfig config = new SubscriptionGroupConfig();
CompletableFuture<Void> actual = mqClientAdminImpl.updateOrCreateSubscriptionGroup(defaultBrokerAddr, config, defaultTimeout);
assertNull(actual.get());
}
@@ -214,7 +214,7 @@ public class MqClientAdminImplTest {
@Test
public void assertUpdateOrCreateSubscriptionGroupWithError() {
setResponseError();
- SubscriptionGroupConfig config = mock(SubscriptionGroupConfig.class);
+ SubscriptionGroupConfig config = new SubscriptionGroupConfig();
CompletableFuture<Void> actual = mqClientAdminImpl.updateOrCreateSubscriptionGroup(defaultBrokerAddr, config, defaultTimeout);
Throwable thrown = assertThrows(ExecutionException.class, actual::get);
assertTrue(thrown.getCause() instanceof MQClientException);
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/consumer/PopProcessQueueTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/PopProcessQueueTest.java
new file mode 100644
index 0000000000..0633342c59
--- /dev/null
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/PopProcessQueueTest.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.client.impl.consumer;
+
+import org.apache.rocketmq.remoting.protocol.body.PopProcessQueueInfo;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PopProcessQueueTest {
+
+ private final PopProcessQueueInfo popProcessQueueInfo = new PopProcessQueueInfo();
+
+ @Test
+ public void testPopProcessQueue() {
+ long currentTime = System.currentTimeMillis();
+ PopProcessQueue popRequest1 = createPopProcessQueue(currentTime);
+ PopProcessQueue popRequest2 = createPopProcessQueue(currentTime);
+ assertEquals(popRequest1.getLastPopTimestamp(), popRequest2.getLastPopTimestamp());
+ assertEquals(popRequest1.toString(), popRequest2.toString());
+ assertEquals(popRequest1.getWaiAckMsgCount(), popRequest2.getWaiAckMsgCount());
+ assertEquals(popRequest1.ack(), popRequest2.ack());
+ assertEquals(popRequest1.isPullExpired(), popRequest2.isPullExpired());
+ assertEquals(popProcessQueueInfo.getLastPopTimestamp(), popRequest1.getLastPopTimestamp());
+ assertEquals(popProcessQueueInfo.isDroped(), popRequest1.isDropped());
+ assertEquals(popProcessQueueInfo.getWaitAckCount(), popRequest1.getWaiAckMsgCount() + popRequest2.getWaiAckMsgCount());
+ }
+
+ private PopProcessQueue createPopProcessQueue(final long currentTime) {
+ PopProcessQueue result = new PopProcessQueue();
+ long curTime = System.currentTimeMillis();
+ result.setLastPopTimestamp(curTime);
+ result.incFoundMsg(1);
+ result.decFoundMsg(1);
+ result.setLastPopTimestamp(currentTime);
+ result.fillPopProcessQueueInfo(popProcessQueueInfo);
+ return result;
+ }
+}
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java
index dd7ffa757f..a12633be1b 100644
--- a/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java
@@ -16,11 +16,6 @@
*/
package org.apache.rocketmq.client.impl.consumer;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.TreeMap;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQBrokerException;
@@ -34,6 +29,12 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.TreeMap;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -164,6 +165,7 @@ public class ProcessQueueTest {
ProcessQueue result = new ProcessQueue();
result.setMsgAccCnt(1);
result.incTryUnlockTimes();
+ result.setLastPullTimestamp(10000L);
return result;
}
diff --git a/client/src/test/java/org/apache/rocketmq/client/producer/SendResultTest.java b/client/src/test/java/org/apache/rocketmq/client/producer/SendResultTest.java
new file mode 100644
index 0000000000..1ae8371a96
--- /dev/null
+++ b/client/src/test/java/org/apache/rocketmq/client/producer/SendResultTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.client.producer;
+
+import com.alibaba.fastjson2.JSON;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class SendResultTest {
+
+ @Test
+ public void testEncoderSendResultToJson() {
+ SendResult sendResult = new SendResult();
+ sendResult.setSendStatus(SendStatus.SEND_OK);
+ sendResult.setMsgId("12345");
+ sendResult.setQueueOffset(100L);
+ MessageQueue messageQueue = new MessageQueue("TestTopic", "BrokerA", 1);
+ sendResult.setMessageQueue(messageQueue);
+
+ String json = SendResult.encoderSendResultToJson(sendResult);
+
+ SendResult decodedResult = JSON.parseObject(json, SendResult.class);
+ assertEquals(sendResult.getSendStatus(), decodedResult.getSendStatus());
+ assertEquals(sendResult.getMsgId(), decodedResult.getMsgId());
+ assertEquals(sendResult.getQueueOffset(), decodedResult.getQueueOffset());
+ assertEquals(sendResult.getMessageQueue(), decodedResult.getMessageQueue());
+ }
+
+ @Test
+ public void testDecoderSendResultFromJson() {
+ String json = "{\"sendStatus\":\"SEND_OK\",\"msgId\":\"12345\",\"queueOffset\":100,\"messageQueue\":{\"topic\":\"TestTopic\",\"brokerName\":\"BrokerA\",\"queueId\":1}}";
+
+ SendResult sendResult = SendResult.decoderSendResultFromJson(json);
+
+ assertEquals(SendStatus.SEND_OK, sendResult.getSendStatus());
+ assertEquals("12345", sendResult.getMsgId());
+ assertEquals(100L, sendResult.getQueueOffset());
+ assertEquals("TestTopic", sendResult.getMessageQueue().getTopic());
+ assertEquals("BrokerA", sendResult.getMessageQueue().getBrokerName());
+ assertEquals(1, sendResult.getMessageQueue().getQueueId());
+ }
+}
diff --git a/common/BUILD.bazel b/common/BUILD.bazel
index 10c5d19fbe..8aeeb2f24f 100644
--- a/common/BUILD.bazel
+++ b/common/BUILD.bazel
@@ -21,7 +21,6 @@ java_library(
srcs = glob(["src/main/java/**/*.java"]),
visibility = ["//visibility:public"],
deps = [
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_github_luben_zstd_jni",
"@maven//:com_google_guava_guava",
@@ -55,7 +54,6 @@ java_library(
":common",
"//:test_deps",
"@maven//:com_google_guava_guava",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:commons_codec_commons_codec",
"@maven//:io_netty_netty_all",
diff --git a/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java b/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java
index 0bf64905a0..ebb009c567 100644
--- a/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java
+++ b/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java
@@ -16,14 +16,15 @@
*/
package org.apache.rocketmq.common;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
+import com.alibaba.fastjson2.annotation.JSONField;
+import org.apache.rocketmq.common.attribute.TopicMessageType;
+import org.apache.rocketmq.common.constant.PermName;
+
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
-import org.apache.rocketmq.common.attribute.TopicMessageType;
-import org.apache.rocketmq.common.constant.PermName;
import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE;
diff --git a/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java b/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java
index 80a1554d12..f2639b51c1 100644
--- a/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java
+++ b/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java
@@ -17,11 +17,10 @@
package org.apache.rocketmq.common.fastjson;
-import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.parser.DefaultJSONParser;
-import com.alibaba.fastjson.parser.JSONToken;
-import com.alibaba.fastjson.parser.deserializer.MapDeserializer;
-import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
+import com.alibaba.fastjson2.JSONException;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.reader.ObjectReader;
+
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
@@ -29,32 +28,40 @@ import java.util.Map;
/**
* workaround https://github.com/alibaba/fastjson/issues/3730
*/
-public class GenericMapSuperclassDeserializer implements ObjectDeserializer {
+public class GenericMapSuperclassDeserializer implements ObjectReader<Object> {
public static final GenericMapSuperclassDeserializer INSTANCE = new GenericMapSuperclassDeserializer();
-
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
- public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
+ public Object readObject(JSONReader reader, Type type, Object fieldName, long features) {
Class<?> clz = (Class<?>) type;
Type genericSuperclass = clz.getGenericSuperclass();
Map map;
try {
- map = (Map) clz.newInstance();
+ map = (Map) clz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new JSONException("unsupport type " + type, e);
}
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type keyType = parameterizedType.getActualTypeArguments()[0];
Type valueType = parameterizedType.getActualTypeArguments()[1];
- if (String.class == keyType) {
- return (T) MapDeserializer.parseMap(parser, (Map<String, Object>) map, valueType, fieldName);
- } else {
- return (T) MapDeserializer.parseMap(parser, map, keyType, valueType, fieldName);
+
+ if (!reader.nextIfObjectStart()) {
+ throw new JSONException(reader.info("expect '{', but " + reader.current()));
}
- }
- @Override
- public int getFastMatchToken() {
- return JSONToken.LBRACE;
+ while (!reader.nextIfObjectEnd()) {
+ Object key;
+ if (keyType == String.class) {
+ key = reader.readFieldName();
+ } else {
+ key = reader.getContext().getProvider().getObjectReader(keyType).readObject(reader, keyType, fieldName, features);
+ reader.nextIfMatch(':');
+ }
+
+ Object value = reader.getContext().getProvider().getObjectReader(valueType).readObject(reader, valueType, fieldName, features);
+ map.put(key, value);
+ reader.nextIfComma();
+ }
+ return map;
}
}
diff --git a/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java b/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java
index 600054b40b..943e823566 100644
--- a/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java
+++ b/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java
@@ -16,23 +16,13 @@
*/
package org.apache.rocketmq.common.utils;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.support.config.FastJsonConfig;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.SerializationException;
/**
* The object serializer based on fastJson
*/
public class FastJsonSerializer implements Serializer {
- private FastJsonConfig fastJsonConfig = new FastJsonConfig();
-
- public FastJsonConfig getFastJsonConfig() {
- return this.fastJsonConfig;
- }
-
- public void setFastJsonConfig(FastJsonConfig fastJsonConfig) {
- this.fastJsonConfig = fastJsonConfig;
- }
@Override
public <T> byte[] serialize(T t) throws SerializationException {
@@ -40,7 +30,7 @@ public class FastJsonSerializer implements Serializer {
return new byte[0];
} else {
try {
- return JSON.toJSONBytes(this.fastJsonConfig.getCharset(), t, this.fastJsonConfig.getSerializeConfig(), this.fastJsonConfig.getSerializeFilters(), this.fastJsonConfig.getDateFormat(), JSON.DEFAULT_GENERATE_FEATURE, this.fastJsonConfig.getSerializerFeatures());
+ return JSON.toJSONBytes(t);
} catch (Exception var3) {
throw new SerializationException("Could not serialize: " + var3.getMessage(), var3);
}
@@ -51,7 +41,7 @@ public class FastJsonSerializer implements Serializer {
public <T> T deserialize(byte[] bytes, Class<T> type) throws SerializationException {
if (bytes != null && bytes.length != 0) {
try {
- return JSON.parseObject(bytes, this.fastJsonConfig.getCharset(), type, this.fastJsonConfig.getParserConfig(), this.fastJsonConfig.getParseProcess(), JSON.DEFAULT_PARSER_FEATURE, this.fastJsonConfig.getFeatures());
+ return JSON.parseObject(bytes, type);
} catch (Exception var3) {
throw new SerializationException("Could not deserialize: " + var3.getMessage(), var3);
}
diff --git a/common/src/test/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializerTest.java b/common/src/test/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializerTest.java
new file mode 100644
index 0000000000..36c633f699
--- /dev/null
+++ b/common/src/test/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializerTest.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.common.fastjson;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONException;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class GenericMapSuperclassDeserializerTest {
+
+ public static class CustomMap extends HashMap<String, Object> {
+ private static final long serialVersionUID = 1L;
+ }
+
+ public static class IntKeyMap extends HashMap<Integer, String> {
+ private static final long serialVersionUID = 1L;
+ }
+
+ @Test
+ public void testBasicDeserialization() {
+ JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+ String json = "{\"key1\":\"value1\",\"key2\":42,\"key3\":true}";
+ CustomMap map = JSON.parseObject(json, CustomMap.class);
+
+ assertNotNull(map);
+ assertEquals(3, map.size());
+ assertEquals("value1", map.get("key1"));
+ assertEquals(42, map.get("key2"));
+ assertEquals(true, map.get("key3"));
+ }
+
+ @Test
+ public void testNestedObjects() {
+ JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+ String json = "{\"simple\":\"value\",\"nested\":{\"inner\":123},\"array\":[1,2,3]}";
+ CustomMap map = JSON.parseObject(json, CustomMap.class);
+
+ assertNotNull(map);
+ assertEquals(3, map.size());
+ assertEquals("value", map.get("simple"));
+
+ assertTrue(map.get("nested") instanceof Map);
+ Map<?, ?> nestedMap = (Map<?, ?>) map.get("nested");
+ assertEquals(123, nestedMap.get("inner"));
+
+ assertTrue(map.get("array") instanceof java.util.List);
+ java.util.List<?> array = (java.util.List<?>) map.get("array");
+ assertEquals(3, array.size());
+ assertEquals(1, array.get(0));
+ assertEquals(2, array.get(1));
+ assertEquals(3, array.get(2));
+ }
+
+ @Test
+ public void testEmptyObject() {
+ JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+ String json = "{}";
+ CustomMap map = JSON.parseObject(json, CustomMap.class);
+
+ assertNotNull(map);
+ assertEquals(0, map.size());
+ }
+
+ @Test
+ public void testNonStringKey() {
+ JSON.registerIfAbsent(IntKeyMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+ String json = "{1:\"one\",2:\"two\",3:\"three\"}";
+ IntKeyMap map = JSON.parseObject(json, IntKeyMap.class);
+
+ assertNotNull(map);
+ assertEquals(3, map.size());
+ assertEquals("one", map.get(1));
+ assertEquals("two", map.get(2));
+ assertEquals("three", map.get(3));
+ }
+
+ @Test(expected = JSONException.class)
+ public void testMalformedJson() {
+ JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+ String json = "{\"key\":\"missing closing brace\"";
+ JSON.parseObject(json, CustomMap.class);
+ }
+}
diff --git a/container/BUILD.bazel b/container/BUILD.bazel
index 4888de2228..b828c4c431 100644
--- a/container/BUILD.bazel
+++ b/container/BUILD.bazel
@@ -35,7 +35,6 @@ java_library(
"@maven//:commons_codec_commons_codec",
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
- "@maven//:com_alibaba_fastjson",
"@maven//:io_netty_netty_all",
"@maven//:com_google_guava_guava",
"@maven//:org_slf4j_slf4j_api",
@@ -65,7 +64,6 @@ java_library(
"@maven//:org_apache_commons_commons_lang3",
"@maven//:io_netty_netty_all",
"@maven//:com_google_guava_guava",
- "@maven//:com_alibaba_fastjson",
],
resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"])
)
diff --git a/controller/BUILD.bazel b/controller/BUILD.bazel
index e1dc61c500..652dbd4d0c 100644
--- a/controller/BUILD.bazel
+++ b/controller/BUILD.bazel
@@ -31,7 +31,7 @@ java_library(
"@maven//:commons_codec_commons_codec",
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:io_netty_netty_all",
"@maven//:com_google_guava_guava",
"@maven//:org_slf4j_slf4j_api",
@@ -70,7 +70,7 @@ java_library(
"@maven//:org_apache_commons_commons_lang3",
"@maven//:io_netty_netty_all",
"@maven//:com_google_guava_guava",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
],
resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"])
)
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java b/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java
index c7d5d26fd0..e7a3443001 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java
@@ -16,8 +16,8 @@
*/
package org.apache.rocketmq.controller.impl.heartbeat;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
import io.netty.channel.Channel;
import org.apache.rocketmq.common.ControllerConfig;
import org.apache.rocketmq.common.ThreadFactoryImpl;
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java b/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java
index 492043235b..046ced90c0 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.controller.impl.manager;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import org.apache.rocketmq.common.ControllerConfig;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.controller.helper.BrokerValidPredicate;
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java
index 3c28158982..ee742cc55b 100644
--- a/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java
@@ -16,13 +16,9 @@
*/
package org.apache.rocketmq.controller.impl;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import io.netty.channel.Channel;
import io.netty.channel.DefaultChannelPromise;
-import java.util.Collections;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.common.ControllerConfig;
import org.apache.rocketmq.controller.impl.heartbeat.BrokerIdentityInfo;
import org.apache.rocketmq.controller.impl.heartbeat.RaftBrokerHeartBeatManager;
@@ -34,6 +30,11 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/event/EventSerializerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/EventSerializerTest.java
new file mode 100644
index 0000000000..4eb482da64
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/EventSerializerTest.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.controller.impl.event;
+
+import org.apache.commons.lang3.SerializationException;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.common.utils.FastJsonSerializer;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class EventSerializerTest {
+
+ @Mock
+ private FastJsonSerializer serializer;
+
+ private final EventSerializer eventSerializer = new EventSerializer();
+
+ @Before
+ public void init() throws IllegalAccessException {
+ FieldUtils.writeDeclaredField(eventSerializer, "serializer", serializer, true);
+ }
+
+ @Test
+ public void testSerializeValidEventMessageShouldReturnSerializedData() {
+ EventMessage eventMessage = mock(EventMessage.class);
+ EventType eventType = EventType.APPLY_BROKER_ID_EVENT;
+ when(eventMessage.getEventType()).thenReturn(eventType);
+ when(serializer.serialize(eventMessage)).thenReturn("{\"event\":\"APPLY_BROKER_ID_EVENT\"}".getBytes());
+ byte[] result = eventSerializer.serialize(eventMessage);
+ assertNotNull(result);
+ }
+
+ @Test
+ public void testSerializeEventMessageWithNoEventType() {
+ EventMessage eventMessage = mock(EventMessage.class);
+ when(eventMessage.getEventType()).thenReturn(null);
+ assertThrows(NullPointerException.class, () -> eventSerializer.serialize(eventMessage));
+ }
+
+ @Test
+ public void testSerializeSerializerReturnsNullShouldReturnNull() {
+ EventMessage eventMessage = mock(EventMessage.class);
+ EventType eventType = EventType.READ_EVENT;
+ when(eventMessage.getEventType()).thenReturn(eventType);
+ when(serializer.serialize(eventMessage)).thenReturn(null);
+ byte[] result = eventSerializer.serialize(eventMessage);
+ assertNull(result);
+ }
+
+ @Test
+ public void testSerializeSerializerThrowsException() {
+ EventMessage eventMessage = mock(EventMessage.class);
+ EventType eventType = EventType.ELECT_MASTER_EVENT;
+ when(eventMessage.getEventType()).thenReturn(eventType);
+ when(serializer.serialize(eventMessage)).thenThrow(new RuntimeException("Serialization error"));
+ assertThrows(RuntimeException.class, () -> eventSerializer.serialize(eventMessage));
+ }
+
+ @Test
+ public void testDeserializeBytesLessThanTwoReturnsNull() {
+ byte[] bytes = new byte[1];
+ assertNull(eventSerializer.deserialize(bytes));
+ }
+
+ @Test
+ public void testDeserializeInvalidEventIdReturnsNull() {
+ assertNull(eventSerializer.deserialize(new byte[]{0, 0xF}));
+ }
+
+ @Test
+ public void testDeserializeValidEventTypeReturnsEventMessage() throws SerializationException {
+ byte[] data = new byte[]{0, 0xF};
+ byte[] bytes = new byte[]{0, (byte) EventType.ALTER_SYNC_STATE_SET_EVENT.getId(), data[0], data[1]};
+ AlterSyncStateSetEvent alterSyncStateSetEvent = mock(AlterSyncStateSetEvent.class);
+ when(serializer.deserialize(any(byte[].class), eq(AlterSyncStateSetEvent.class))).thenReturn(alterSyncStateSetEvent);
+ EventMessage result = eventSerializer.deserialize(bytes);
+ assertNotNull(result);
+ assertTrue(result instanceof AlterSyncStateSetEvent);
+ }
+
+ @Test
+ public void testDeserializeSerializerThrowsException() throws SerializationException {
+ byte[] data = new byte[]{0, 0xF};
+ byte[] bytes = new byte[]{0, (byte) EventType.ALTER_SYNC_STATE_SET_EVENT.getId(), data[0], data[1]};
+ when(serializer.deserialize(any(byte[].class), eq(AlterSyncStateSetEvent.class))).thenThrow(new SerializationException("Deserialization failed"));
+ assertThrows(SerializationException.class, () -> eventSerializer.deserialize(bytes));
+ }
+
+ @Test
+ public void testDeserializeValidEventTypeUnknownEventReturnsNull() throws SerializationException {
+ byte[] data = new byte[]{0, 0xF};
+ byte[] bytes = new byte[]{0, (short) 99, data[0], data[1]};
+ assertNull(eventSerializer.deserialize(bytes));
+ }
+}
\ No newline at end of file
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/event/ListEventSerializerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/ListEventSerializerTest.java
new file mode 100644
index 0000000000..1c5e7f3a04
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/ListEventSerializerTest.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.controller.impl.event;
+
+import org.apache.commons.lang3.SerializationException;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ListEventSerializerTest {
+
+ @Mock
+ private Logger logger;
+
+ @Test
+ public void testSerializeEmptyList() {
+ List<EventMessage> events = Collections.emptyList();
+ byte[] result = ListEventSerializer.serialize(events, null);
+ assertNotNull(result);
+ assertEquals(0, result.length);
+ }
+
+ @Test
+ public void testSerializeValidEventMessage() {
+ EventMessage eventMessage = new ElectMasterEvent("brokerA", 0L);
+ List<EventMessage> events = Collections.singletonList(eventMessage);
+ byte[] result = ListEventSerializer.serialize(events, null);
+ assertNotNull(result);
+ assertTrue(result.length > 0);
+ }
+
+ @Test
+ public void testSerializeEventMessageWithNullEventType() {
+ EventMessage eventMessage = mock(EventMessage.class);
+ when(eventMessage.getEventType()).thenReturn(null);
+ List<EventMessage> events = Collections.singletonList(eventMessage);
+ assertThrows(NullPointerException.class, () -> ListEventSerializer.serialize(events, logger));
+ }
+
+ @Test
+ public void testDeserializeBytesIsNull() throws SerializationException {
+ List<EventMessage> result = ListEventSerializer.deserialize(null, logger);
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testDeserializeBytesLengthLessThanSix() throws SerializationException {
+ byte[] bytes = new byte[5];
+ List<EventMessage> result = ListEventSerializer.deserialize(bytes, logger);
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testDeserializeValidBytesWithKnownEventType() throws SerializationException {
+ byte[] bytes = new byte[]{0x01, 0x00, 0x06, 0x00, 0x00, 0x00};
+ assertNotNull(ListEventSerializer.deserialize(bytes, logger));
+ }
+
+ @Test
+ public void testDeserializeException() throws SerializationException {
+ byte[] bytes = new byte[]{0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00};
+ assertThrows(ArrayIndexOutOfBoundsException.class, () -> ListEventSerializer.deserialize(bytes, logger));
+ }
+}
\ No newline at end of file
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManagerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManagerTest.java
new file mode 100644
index 0000000000..28c370abbe
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManagerTest.java
@@ -0,0 +1,352 @@
+/*
+ * 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.controller.impl.heartbeat;
+
+import com.alibaba.fastjson2.JSON;
+import io.netty.channel.Channel;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.common.ControllerConfig;
+import org.apache.rocketmq.common.JraftConfig;
+import org.apache.rocketmq.controller.impl.JRaftController;
+import org.apache.rocketmq.controller.impl.task.BrokerCloseChannelRequest;
+import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerRequest;
+import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoResponse;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RaftBrokerHeartBeatManagerTest {
+
+ @Mock
+ private JRaftController controller;
+
+ private RaftBrokerHeartBeatManager raftBrokerHeartBeatManager;
+
+ @Before
+ public void init() throws IllegalAccessException {
+ ControllerConfig controllerConfig = new ControllerConfig();
+ raftBrokerHeartBeatManager = new RaftBrokerHeartBeatManager(controllerConfig);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "controller", controller, true);
+ }
+
+ @Test
+ public void testOnBrokerHeartbeatSuccess() {
+ Channel channel = mock(Channel.class);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ when(controller.onBrokerHeartBeat(any())).thenReturn(future);
+ raftBrokerHeartBeatManager.onBrokerHeartbeat("cluster1", "broker1", "127.0.0.1:10911", 1L, 3000L, channel, 1, 1000L, 500L, 1);
+ verify(channel, never()).close();
+ }
+
+ @Test
+ public void testOnBrokerHeartbeatLeaderNotAvailable() {
+ Channel channel = mock(Channel.class);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.CONTROLLER_NOT_LEADER, "Not Leader"));
+ when(controller.onBrokerHeartBeat(any())).thenReturn(future);
+ raftBrokerHeartBeatManager.onBrokerHeartbeat("cluster1", "broker1", "127.0.0.1:10911", 1L, 3000L, channel, 1, 1000L, 500L, 1);
+ verify(channel, never()).close();
+ }
+
+ @Test
+ public void testOnBrokerHeartbeatException() throws Exception {
+ Channel channel = mock(Channel.class);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ when(controller.onBrokerHeartBeat(any())).thenReturn(future);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", null, true);
+ assertThrows(NullPointerException.class, () -> raftBrokerHeartBeatManager.onBrokerHeartbeat("cluster1", "broker1", "127.0.0.1:10911", 1L, 3000L, channel, 1, 1000L, 500L, 1));
+ }
+
+ @Test
+ public void testOnBrokerChannelCloseBrokerIdentityInfoNotNullSuccess() throws Exception {
+ Channel channel = mock(Channel.class);
+ BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo("cluster1", "broker1", 1L);
+ Map<Channel, BrokerIdentityInfo> brokerChannelIdentityInfoMap = new HashMap<>();
+ brokerChannelIdentityInfoMap.put(channel, brokerIdentityInfo);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelIdentityInfoMap, true);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ when(controller.onBrokerCloseChannel(any(BrokerCloseChannelRequest.class))).thenReturn(future);
+ raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+ verify(controller).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+ }
+
+ @Test
+ public void testOnBrokerChannelCloseBrokerIdentityInfoNotNullException() throws Exception {
+ Channel channel = mock(Channel.class);
+ BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo("cluster1", "broker1", 1L);
+ Map<Channel, BrokerIdentityInfo> brokerChannelIdentityInfoMap = new HashMap<>();
+ brokerChannelIdentityInfoMap.put(channel, brokerIdentityInfo);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelIdentityInfoMap, true);
+ CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+ future.completeExceptionally(new ExecutionException(new RuntimeException("Test Exception")));
+ when(controller.onBrokerCloseChannel(any(BrokerCloseChannelRequest.class))).thenReturn(future);
+ raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+ verify(controller).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+ }
+
+ @Test
+ public void testOnBrokerChannelCloseBrokerIdentityInfoNull() {
+ Channel channel = mock(Channel.class);
+ raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+ verify(controller, never()).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+ }
+
+ @Test
+ public void testOnBrokerChannelCloseBrokerIdentityInfoNotNullTimeoutException() throws Exception {
+ Channel channel = mock(Channel.class);
+ BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo("cluster1", "broker1", 1L);
+ Map<Channel, BrokerIdentityInfo> brokerChannelIdentityInfoMap = new HashMap<>();
+ brokerChannelIdentityInfoMap.put(channel, brokerIdentityInfo);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelIdentityInfoMap, true);
+ CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+ when(controller.onBrokerCloseChannel(any(BrokerCloseChannelRequest.class))).thenReturn(future);
+ raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+ verify(controller).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+ }
+
+ @Test
+ public void testScanNotActiveBrokerSuccess() throws Exception {
+ ControllerConfig controllerConfig = new ControllerConfig();
+ JraftConfig jraftConfig = new JraftConfig();
+ jraftConfig.setjRaftScanWaitTimeoutMs(10000);
+ controllerConfig.setJraftConfig(jraftConfig);
+ raftBrokerHeartBeatManager = new RaftBrokerHeartBeatManager(controllerConfig);
+ controller = mock(JRaftController.class);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "controller", controller, true);
+ when(controller.isLeaderState()).thenReturn(true);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "firstReceivedHeartbeatTime", 1000, true);
+
+ List<BrokerIdentityInfo> inactiveBrokers = new ArrayList<>();
+ BrokerIdentityInfo brokerInfo = new BrokerIdentityInfo("testCluster", "testBroker", 1L);
+ inactiveBrokers.add(brokerInfo);
+
+ RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success");
+ response.setBody(JSON.toJSONString(inactiveBrokers).getBytes());
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(response);
+ when(controller.checkNotActiveBroker(any())).thenReturn(future);
+
+ Channel channel = mock(Channel.class);
+ Map<Channel, BrokerIdentityInfo> brokerChannelMap = new HashMap<>();
+ brokerChannelMap.put(channel, brokerInfo);
+ FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelMap, true);
+
+ Method method = RaftBrokerHeartBeatManager.class.getDeclaredMethod("scanNotActiveBroker");
+ method.setAccessible(true);
+ method.invoke(raftBrokerHeartBeatManager);
+
+ verify(controller).checkNotActiveBroker(any(CheckNotActiveBrokerRequest.class));
+ }
+
+ @Test
+ public void testGetBrokerLiveInfoSuccess() throws Exception {
+ String clusterName = "cluster1";
+ String brokerName = "broker1";
+ Long brokerId = 1L;
+ BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo(clusterName, brokerName, brokerId);
+ BrokerLiveInfo expectedBrokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> expectedResponse = new HashMap<>();
+ expectedResponse.put(brokerIdentityInfo, expectedBrokerLiveInfo);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(expectedResponse).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ BrokerLiveInfo brokerLiveInfo = raftBrokerHeartBeatManager.getBrokerLiveInfo(clusterName, brokerName, brokerId);
+ assertEquals(expectedBrokerLiveInfo.getBrokerName(), brokerLiveInfo.getBrokerName());
+ assertEquals(expectedBrokerLiveInfo.getBrokerAddr(), brokerLiveInfo.getBrokerAddr());
+ assertEquals(expectedBrokerLiveInfo.getBrokerId(), brokerLiveInfo.getBrokerId());
+ }
+
+ @Test
+ public void testGetBrokerLiveInfoAllBrokers() throws Exception {
+ String clusterName = "cluster1";
+ String brokerName = "broker1";
+ Long brokerId = 1L;
+ BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo(clusterName, brokerName, brokerId);
+ BrokerLiveInfo expectedBrokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> expectedResponse = new HashMap<>();
+ expectedResponse.put(brokerIdentityInfo, expectedBrokerLiveInfo);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(expectedResponse).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ BrokerLiveInfo brokerLiveInfo = raftBrokerHeartBeatManager.getBrokerLiveInfo(null, null, null);
+ assertNull(brokerLiveInfo);
+ }
+
+ @Test
+ public void testIsBrokerActiveBrokerActive() throws Exception {
+ String clusterName = "cluster1";
+ String brokerName = "broker1";
+ Long brokerId = 1L;
+ BrokerLiveInfo brokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+ responseMap.put(new BrokerIdentityInfo(clusterName, brokerName, brokerId), brokerLiveInfo);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ assertTrue(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+ }
+
+ @Test
+ public void testIsBrokerActiveBrokerNotActive() throws Exception {
+ String clusterName = "cluster1";
+ String brokerName = "broker1";
+ Long brokerId = 1L;
+ BrokerLiveInfo brokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis() - 4000L, 3000L, null, 1, 1000L, 500);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+ responseMap.put(new BrokerIdentityInfo(clusterName, brokerName, brokerId), brokerLiveInfo);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+ }
+
+ @Test
+ public void testIsBrokerActiveException() {
+ String clusterName = "cluster1";
+ String brokerName = "broker1";
+ Long brokerId = 1L;
+ CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+ future.completeExceptionally(new ExecutionException(new RuntimeException("Test Exception")));
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+ }
+
+ @Test
+ public void testIsBrokerActiveNoInfo() throws Exception {
+ String clusterName = "cluster1";
+ String brokerName = "broker1";
+ Long brokerId = 1L;
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(new HashMap<BrokerIdentityInfo, BrokerLiveInfo>()).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+ }
+
+ @Test
+ public void testIsBrokerActiveInvalidResponseCode() {
+ String clusterName = "cluster1";
+ String brokerName = "broker1";
+ Long brokerId = 1L;
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.RPC_TIME_OUT, "Timeout"));
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+ }
+
+ @Test
+ public void testGetActiveBrokersNumAllBrokers() throws Exception {
+ String clusterName1 = "cluster1";
+ String brokerName1 = "broker1";
+ Long brokerId1 = 1L;
+ String clusterName2 = "cluster2";
+ String brokerName2 = "broker2";
+ Long brokerId2 = 2L;
+ BrokerIdentityInfo brokerIdentityInfo1 = new BrokerIdentityInfo(clusterName1, brokerName1, brokerId1);
+ BrokerIdentityInfo brokerIdentityInfo2 = new BrokerIdentityInfo(clusterName2, brokerName2, brokerId2);
+ BrokerLiveInfo brokerLiveInfo1 = new BrokerLiveInfo(brokerName1, "127.0.0.1:10911", brokerId1, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+ BrokerLiveInfo brokerLiveInfo2 = new BrokerLiveInfo(brokerName2, "127.0.0.1:10912", brokerId2, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+ responseMap.put(brokerIdentityInfo1, brokerLiveInfo1);
+ responseMap.put(brokerIdentityInfo2, brokerLiveInfo2);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+ assertEquals(2, activeBrokersNum.size());
+ assertEquals(1, activeBrokersNum.get(clusterName1).size());
+ assertEquals(1, activeBrokersNum.get(clusterName2).size());
+ assertEquals(1, (int) activeBrokersNum.get(clusterName1).get(brokerName1));
+ assertEquals(1, (int) activeBrokersNum.get(clusterName2).get(brokerName2));
+ }
+
+ @Test
+ public void testGetActiveBrokersNum() throws Exception {
+ String clusterName1 = "cluster1";
+ String brokerName1 = "broker1";
+ Long brokerId1 = 1L;
+ String clusterName2 = "cluster2";
+ String brokerName2 = "broker2";
+ Long brokerId2 = 2L;
+ BrokerIdentityInfo brokerIdentityInfo1 = new BrokerIdentityInfo(clusterName1, brokerName1, brokerId1);
+ BrokerIdentityInfo brokerIdentityInfo2 = new BrokerIdentityInfo(clusterName2, brokerName2, brokerId2);
+ BrokerLiveInfo brokerLiveInfo1 = new BrokerLiveInfo(brokerName1, "127.0.0.1:10911", brokerId1, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+ BrokerLiveInfo brokerLiveInfo2 = new BrokerLiveInfo(brokerName2, "127.0.0.1:10912", brokerId2, System.currentTimeMillis() - 4000L, 3000L, null, 1, 1000L, 500);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+ responseMap.put(brokerIdentityInfo1, brokerLiveInfo1);
+ responseMap.put(brokerIdentityInfo2, brokerLiveInfo2);
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+ assertEquals(1, activeBrokersNum.size());
+ }
+
+ @Test
+ public void testGetActiveBrokersNumException() {
+ CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+ future.completeExceptionally(new ExecutionException(new RuntimeException("Test Exception")));
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+ assertTrue(activeBrokersNum.isEmpty());
+ }
+
+ @Test
+ public void testGetActiveBrokersNumNoBrokers() throws Exception {
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+ future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+ future.get().setBody(JSON.toJSONString(new HashMap<BrokerIdentityInfo, BrokerLiveInfo>()).getBytes());
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+ assertTrue(activeBrokersNum.isEmpty());
+ }
+
+ @Test
+ public void testGetActiveBrokersNumInvalidResponseCode() {
+ CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.RPC_TIME_OUT, "Timeout"));
+ when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+ Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+ assertTrue(activeBrokersNum.isEmpty());
+ }
+}
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManagerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManagerTest.java
new file mode 100644
index 0000000000..b47f072c2c
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManagerTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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.controller.impl.manager;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.common.ControllerConfig;
+import org.apache.rocketmq.controller.impl.event.ControllerResult;
+import org.apache.rocketmq.controller.impl.heartbeat.BrokerIdentityInfo;
+import org.apache.rocketmq.controller.impl.heartbeat.BrokerLiveInfo;
+import org.apache.rocketmq.controller.impl.task.BrokerCloseChannelRequest;
+import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerRequest;
+import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerResponse;
+import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoRequest;
+import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoResponse;
+import org.apache.rocketmq.controller.impl.task.RaftBrokerHeartBeatEventRequest;
+import org.apache.rocketmq.controller.impl.task.RaftBrokerHeartBeatEventResponse;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RaftReplicasInfoManagerTest {
+
+ @Mock
+ private ControllerConfig controllerConfig;
+
+ private RaftReplicasInfoManager raftReplicasInfoManager;
+
+ @Before
+ public void init() {
+ raftReplicasInfoManager = new RaftReplicasInfoManager(controllerConfig);
+ }
+
+ @Test
+ public void testGetBrokerLiveInfoBrokerIdentityInfoIsNullReturnsAllBrokersInfo() throws IllegalAccessException {
+ List<BrokerIdentityInfo> brokerIdentityInfos = createBrokerIdentityInfos(2);
+ List<BrokerLiveInfo> brokerLiveInfos = createBrokerLiveInfos(2);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(brokerIdentityInfos.get(0), brokerLiveInfos.get(0));
+ brokerLiveTable.put(brokerIdentityInfos.get(1), brokerLiveInfos.get(1));
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ GetBrokerLiveInfoRequest request = new GetBrokerLiveInfoRequest();
+ ControllerResult<GetBrokerLiveInfoResponse> result = raftReplicasInfoManager.getBrokerLiveInfo(request);
+ assertNotNull(result);
+ assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+ }
+
+ @Test
+ public void testGetBrokerLiveInfoBrokerIdentityInfoExistsReturnsBrokerInfo() throws IllegalAccessException {
+ BrokerIdentityInfo brokerIdentityInfo = createBrokerIdentityInfo();
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(brokerIdentityInfo, createBrokerLiveInfo());
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ GetBrokerLiveInfoRequest request = new GetBrokerLiveInfoRequest(brokerIdentityInfo);
+ ControllerResult<GetBrokerLiveInfoResponse> result = raftReplicasInfoManager.getBrokerLiveInfo(request);
+ assertNotNull(result);
+ assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+ }
+
+ @Test
+ public void testGetBrokerLiveInfoBrokerIdentityInfoNotExistsReturnsError() {
+ GetBrokerLiveInfoRequest request = new GetBrokerLiveInfoRequest(createBrokerIdentityInfo());
+ ControllerResult<GetBrokerLiveInfoResponse> result = raftReplicasInfoManager.getBrokerLiveInfo(request);
+ assertNotNull(result);
+ assertEquals(ResponseCode.CONTROLLER_BROKER_LIVE_INFO_NOT_EXISTS, result.getResponseCode());
+ }
+
+ @Test
+ public void testOnBrokerHeartBeatNewBrokerRegistered() {
+ RaftBrokerHeartBeatEventRequest request = new RaftBrokerHeartBeatEventRequest(createBrokerIdentityInfo(), createBrokerLiveInfo());
+ ControllerResult<RaftBrokerHeartBeatEventResponse> result = raftReplicasInfoManager.onBrokerHeartBeat(request);
+ assertNotNull(result);
+ assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+ }
+
+ @Test
+ public void testOnBrokerHeartBeatExistingBrokerUpdate() throws IllegalAccessException {
+ BrokerIdentityInfo brokerIdentityInfo = createBrokerIdentityInfo();
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(brokerIdentityInfo, createBrokerLiveInfo());
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ BrokerLiveInfo updatedInfo = new BrokerLiveInfo("brokerName1", "brokerAddr1", 1L, System.currentTimeMillis(), 2000L, null, 2, 200L, 2);
+ RaftBrokerHeartBeatEventRequest request = new RaftBrokerHeartBeatEventRequest(brokerIdentityInfo, updatedInfo);
+ ControllerResult<RaftBrokerHeartBeatEventResponse> result = raftReplicasInfoManager.onBrokerHeartBeat(request);
+ assertNotNull(result);
+ assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+ }
+
+ @Test
+ public void testOnBrokerCloseChannelBrokerIdentityInfoIsNullLogsWarningAndReturnsResult() {
+ assertNotNull(raftReplicasInfoManager.onBrokerCloseChannel(new BrokerCloseChannelRequest()));
+ }
+
+ @Test
+ public void testCheckNotActiveBrokerNoBrokersInTableReturnsEmptyList() {
+ CheckNotActiveBrokerRequest request = new CheckNotActiveBrokerRequest();
+ ControllerResult<CheckNotActiveBrokerResponse> result = raftReplicasInfoManager.checkNotActiveBroker(request);
+ assertNotNull(result);
+ assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+ }
+
+ @Test
+ public void testCheckNotActiveBrokerBrokerLiveTableNotEmptyIdentifiesNotActiveBrokers() throws IllegalAccessException {
+ List<BrokerIdentityInfo> brokerIdentityInfos = createBrokerIdentityInfos(2);
+ List<BrokerLiveInfo> brokerLiveInfos = createBrokerLiveInfos(2);
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(brokerIdentityInfos.get(0), brokerLiveInfos.get(0));
+ brokerLiveTable.put(brokerIdentityInfos.get(1), brokerLiveInfos.get(1));
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ CheckNotActiveBrokerRequest request = new CheckNotActiveBrokerRequest();
+ ControllerResult<CheckNotActiveBrokerResponse> result = raftReplicasInfoManager.checkNotActiveBroker(request);
+ assertNotNull(result);
+ assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+ assertNotNull(result.getBody());
+ }
+
+ @Test
+ public void testCheckNotActiveBrokerSerializeErrorSetsErrorRemark() throws IllegalAccessException {
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ CheckNotActiveBrokerRequest request = new CheckNotActiveBrokerRequest();
+ ControllerResult<CheckNotActiveBrokerResponse> result = raftReplicasInfoManager.checkNotActiveBroker(request);
+ assertNotNull(result);
+ }
+
+ @Test
+ public void testIsBrokerActiveBrokerLiveInfoNotNullAndActiveReturnsTrue() throws IllegalAccessException {
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ long invokeTime = System.currentTimeMillis() + 500;
+ boolean brokerActive = raftReplicasInfoManager.isBrokerActive("cluster0", "broker0", 0L, invokeTime);
+ assertTrue(brokerActive);
+ }
+
+ @Test
+ public void testIsBrokerActiveBrokerLiveInfoNotNullAndNotActiveReturnsFalse() throws IllegalAccessException {
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ long invokeTime = System.currentTimeMillis();
+ assertFalse(raftReplicasInfoManager.isBrokerActive("cluster1", "broker1", 1L, invokeTime));
+ }
+
+ @Test
+ public void testIsBrokerActiveBrokerLiveInfoNullReturnsFalse() {
+ assertFalse(raftReplicasInfoManager.isBrokerActive("cluster1", "broker1", 1L, System.currentTimeMillis()));
+ }
+
+ @Test
+ public void testSerializeWithPopulatedTablesReturnsByteArray() throws Throwable {
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ byte[] result = raftReplicasInfoManager.serialize();
+ assertNotNull(result);
+ assertTrue(result.length > 0);
+ }
+
+ @Test
+ public void testDeserializeFromValidDataSuccess() throws Throwable {
+ BrokerIdentityInfo brokerIdentityInfo = createBrokerIdentityInfo();
+ Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+ brokerLiveTable.put(brokerIdentityInfo, createBrokerLiveInfo());
+ FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+ raftReplicasInfoManager.deserializeFrom(raftReplicasInfoManager.serialize());
+ assertNotNull(brokerLiveTable);
+ assertEquals(1, brokerLiveTable.size());
+ assertTrue(brokerLiveTable.containsKey(brokerIdentityInfo));
+ }
+
+ @Test
+ public void testDeserializeFromInvalidDataExceptionThrown() {
+ byte[] invalidData = new byte[]{0x00, 0x01, 0x02, 0x03};
+ try {
+ raftReplicasInfoManager.deserializeFrom(invalidData);
+ fail("Expected an exception to be thrown");
+ } catch (Throwable e) {
+ assertTrue(e instanceof ArrayIndexOutOfBoundsException);
+ }
+ }
+
+ private BrokerIdentityInfo createBrokerIdentityInfo() {
+ return createBrokerIdentityInfos(1).get(0);
+ }
+
+ private List<BrokerIdentityInfo> createBrokerIdentityInfos(final int count) {
+ List<BrokerIdentityInfo> result = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ result.add(new BrokerIdentityInfo("cluster" + i, "broker" + i, (long) i));
+ }
+ return result;
+ }
+
+ private BrokerLiveInfo createBrokerLiveInfo() {
+ return createBrokerLiveInfos(1).get(0);
+ }
+
+ private List<BrokerLiveInfo> createBrokerLiveInfos(final int count) {
+ List<BrokerLiveInfo> result = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ result.add(new BrokerLiveInfo("brokerName" + i,
+ "brokerAddr" + i,
+ i,
+ System.currentTimeMillis(),
+ 1000L,
+ null,
+ 1,
+ 100L,
+ 1));
+ }
+ return result;
+ }
+}
diff --git a/filter/BUILD.bazel b/filter/BUILD.bazel
index c0d59ba6f4..76e3ef43de 100644
--- a/filter/BUILD.bazel
+++ b/filter/BUILD.bazel
@@ -26,7 +26,6 @@ java_library(
"@maven//:commons_validator_commons_validator",
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
- "@maven//:com_alibaba_fastjson",
"@maven//:io_netty_netty_all",
"@maven//:com_google_guava_guava",
],
diff --git a/namesrv/BUILD.bazel b/namesrv/BUILD.bazel
index fec42eaa3e..435fc29a7f 100644
--- a/namesrv/BUILD.bazel
+++ b/namesrv/BUILD.bazel
@@ -31,7 +31,7 @@ java_library(
"@maven//:commons_validator_commons_validator",
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:io_netty_netty_all",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:ch_qos_logback_logback_core",
@@ -60,7 +60,7 @@ java_library(
"@maven//:commons_cli_commons_cli",
"@maven//:io_netty_netty_all",
"@maven//:com_google_guava_guava",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:io_github_aliyunmq_rocketmq_slf4j_api",
],
resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"])
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java
index 1ef6beadd3..ef653129a7 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java
@@ -17,10 +17,8 @@
package org.apache.rocketmq.namesrv.processor;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSONWriter;
import io.netty.channel.ChannelHandlerContext;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.help.FAQUrl;
@@ -35,6 +33,9 @@ import org.apache.rocketmq.remoting.protocol.ResponseCode;
import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
public class ClientRequestProcessor implements NettyRequestProcessor {
private static Logger log = LoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
@@ -81,9 +82,8 @@ public class ClientRequestProcessor implements NettyRequestProcessor {
byte[] content;
Boolean standardJsonOnly = Optional.ofNullable(requestHeader.getAcceptStandardJsonOnly()).orElse(false);
if (request.getVersion() >= MQVersion.Version.V4_9_4.ordinal() || standardJsonOnly) {
- content = topicRouteData.encode(SerializerFeature.BrowserCompatible,
- SerializerFeature.QuoteFieldNames, SerializerFeature.SkipTransientField,
- SerializerFeature.MapSortField);
+ content = topicRouteData.encode(JSONWriter.Feature.BrowserCompatible,
+ JSONWriter.Feature.MapSortField);
} else {
content = topicRouteData.encode();
}
diff --git a/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessorTest.java b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessorTest.java
new file mode 100644
index 0000000000..6fa88ad6ea
--- /dev/null
+++ b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessorTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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 org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.common.namesrv.NamesrvConfig;
+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.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.RequestCode;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
+import org.apache.rocketmq.remoting.protocol.route.BrokerData;
+import org.apache.rocketmq.remoting.protocol.route.QueueData;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ClientRequestProcessorTest {
+
+ @Mock
+ private NamesrvController namesrvController;
+
+ @Mock
+ private RouteInfoManager routeInfoManager;
+
+ @Mock
+ private NamesrvConfig namesrvConfig;
+
+ @Mock
+ private ChannelHandlerContext ctx;
+
+ private ClientRequestProcessor clientRequestProcessor;
+
+ @Before
+ public void setup() throws NoSuchFieldException, IllegalAccessException {
+ when(namesrvController.getRouteInfoManager()).thenReturn(routeInfoManager);
+ when(namesrvController.getNamesrvConfig()).thenReturn(namesrvConfig);
+
+ when(namesrvConfig.getWaitSecondsForService()).thenReturn(0);
+ when(namesrvConfig.isNeedWaitForService()).thenReturn(true);
+
+ clientRequestProcessor = new ClientRequestProcessor(namesrvController);
+
+ Field startupTimeMillisField = ClientRequestProcessor.class.getDeclaredField("startupTimeMillis");
+ startupTimeMillisField.setAccessible(true);
+ startupTimeMillisField.set(clientRequestProcessor, System.currentTimeMillis() - 60000);
+ }
+
+ @Test
+ public void testGetRouteInfoByTopicWithHighVersionClient() throws RemotingCommandException {
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+ request.setVersion(MQVersion.Version.V4_9_4.ordinal());
+
+ GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+ requestHeader.setTopic("TestTopic");
+
+ RemotingCommand spyRequest = spy(request);
+ doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+ TopicRouteData topicRouteData = createMockTopicRouteData();
+
+ when(routeInfoManager.pickupTopicRouteData("TestTopic")).thenReturn(topicRouteData);
+
+ RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+ assertNotNull(response.getBody());
+ }
+
+ @Test
+ public void testGetRouteInfoByTopicWithLowVersionClientAndNoStandardJsonFlag() throws RemotingCommandException {
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+ request.setVersion(MQVersion.Version.V4_9_3.ordinal());
+
+ GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+ requestHeader.setTopic("TestTopic");
+ requestHeader.setAcceptStandardJsonOnly(false);
+
+ RemotingCommand spyRequest = spy(request);
+ doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+ TopicRouteData topicRouteData = createMockTopicRouteData();
+
+ when(routeInfoManager.pickupTopicRouteData("TestTopic")).thenReturn(topicRouteData);
+
+ RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+ assertNotNull(response.getBody());
+ }
+
+ @Test
+ public void testGetRouteInfoByTopicWithNameServerNotReady() throws RemotingCommandException {
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+
+ GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+ requestHeader.setTopic("TestTopic");
+
+ RemotingCommand spyRequest = spy(request);
+ doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+ when(namesrvConfig.getWaitSecondsForService()).thenReturn(60);
+ when(namesrvConfig.isNeedWaitForService()).thenReturn(true);
+
+ try {
+ Field startupTimeMillisField = ClientRequestProcessor.class.getDeclaredField("startupTimeMillis");
+ startupTimeMillisField.setAccessible(true);
+ startupTimeMillisField.set(clientRequestProcessor, System.currentTimeMillis());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+ assertEquals(ResponseCode.SYSTEM_ERROR, response.getCode());
+ assertEquals("name server not ready", response.getRemark());
+ }
+
+ @Test
+ public void testGetRouteInfoByTopicWithTopicNotExist() throws RemotingCommandException {
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+
+ GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+ requestHeader.setTopic("NonExistentTopic");
+
+ RemotingCommand spyRequest = spy(request);
+ doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+ when(routeInfoManager.pickupTopicRouteData("NonExistentTopic")).thenReturn(null);
+
+ RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+ assertEquals(ResponseCode.TOPIC_NOT_EXIST, response.getCode());
+ assertNotNull(response.getRemark());
+ }
+
+ private TopicRouteData createMockTopicRouteData() {
+ TopicRouteData result = new TopicRouteData();
+
+ List<QueueData> queueDataList = new ArrayList<>();
+ QueueData queueData = new QueueData();
+ queueData.setBrokerName("broker-a");
+ queueData.setReadQueueNums(4);
+ queueData.setWriteQueueNums(4);
+ queueData.setPerm(6);
+ queueData.setTopicSysFlag(0);
+ queueDataList.add(queueData);
+ result.setQueueDatas(queueDataList);
+
+ List<BrokerData> brokerDataList = new ArrayList<>();
+ BrokerData brokerData = new BrokerData();
+ brokerData.setBrokerName("broker-a");
+ brokerData.setCluster("default-cluster");
+ HashMap<Long, String> brokerAddrs = new HashMap<>();
+ brokerAddrs.put(0L, "127.0.0.1:10911");
+ brokerData.setBrokerAddrs(brokerAddrs);
+ brokerDataList.add(brokerData);
+ result.setBrokerDatas(brokerDataList);
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/proxy/BUILD.bazel b/proxy/BUILD.bazel
index 8b7915ba74..5d7fe24435 100644
--- a/proxy/BUILD.bazel
+++ b/proxy/BUILD.bazel
@@ -29,7 +29,6 @@ java_library(
"//srvutil",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:ch_qos_logback_logback_core",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_github_ben_manes_caffeine_caffeine",
"@maven//:com_github_luben_zstd_jni",
@@ -88,7 +87,6 @@ java_library(
"//srvutil",
"//remoting",
"@maven//:ch_qos_logback_logback_core",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_github_ben_manes_caffeine_caffeine",
"@maven//:com_google_guava_guava",
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java
index 5b7c6c3007..175ff438f8 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java
@@ -17,7 +17,7 @@
package org.apache.rocketmq.proxy.config;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import java.io.File;
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java
index 0d8c60931d..4660610ecd 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java
@@ -17,8 +17,8 @@
package org.apache.rocketmq.proxy.config;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter.Feature;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.auth.config.AuthConfig;
import org.apache.rocketmq.common.MixAll;
@@ -59,6 +59,6 @@ public class ConfigurationManager {
public static String formatProxyConfig() {
return JSON.toJSONString(ConfigurationManager.getProxyConfig(),
- SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteNullListAsEmpty);
+ Feature.PrettyFormat, Feature.WriteMapNullValue, Feature.WriteNullListAsEmpty);
}
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java
index a22401a5f3..dba0655c7e 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java
@@ -17,15 +17,16 @@
package org.apache.rocketmq.proxy.processor.channel;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import java.util.HashMap;
-import java.util.Map;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import java.util.HashMap;
+import java.util.Map;
+
public class RemoteChannelSerializer {
private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
private static final String REMOTE_PROXY_IP_KEY = "remoteProxyIp";
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java
index 56ec34fae6..759b74fe5d 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java
@@ -17,15 +17,10 @@
package org.apache.rocketmq.proxy.remoting.activity;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSONWriter;
import com.google.common.net.HostAndPort;
import io.netty.channel.ChannelHandlerContext;
-import java.util.ArrayList;
-import java.util.List;
import org.apache.rocketmq.common.MQVersion;
-import org.apache.rocketmq.remoting.protocol.ResponseCode;
-import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
-import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
import org.apache.rocketmq.proxy.common.Address;
import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
@@ -34,6 +29,12 @@ import org.apache.rocketmq.proxy.processor.MessagingProcessor;
import org.apache.rocketmq.proxy.remoting.pipeline.RequestPipeline;
import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+
+import java.util.ArrayList;
+import java.util.List;
public class GetTopicRouteActivity extends AbstractRemotingActivity {
public GetTopicRouteActivity(RequestPipeline requestPipeline,
@@ -57,9 +58,7 @@ public class GetTopicRouteActivity extends AbstractRemotingActivity {
byte[] content;
Boolean standardJsonOnly = requestHeader.getAcceptStandardJsonOnly();
if (request.getVersion() >= MQVersion.Version.V4_9_4.ordinal() || null != standardJsonOnly && standardJsonOnly) {
- content = topicRouteData.encode(SerializerFeature.BrowserCompatible,
- SerializerFeature.QuoteFieldNames, SerializerFeature.SkipTransientField,
- SerializerFeature.MapSortField);
+ content = topicRouteData.encode(JSONWriter.Feature.BrowserCompatible, JSONWriter.Feature.MapSortField);
} else {
content = topicRouteData.encode();
}
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
index 5dbdea1b2e..ea8a519d5b 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
@@ -17,25 +17,22 @@
package org.apache.rocketmq.proxy.remoting.channel;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
import com.google.common.base.MoreObjects;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelMetadata;
-import java.time.Duration;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.utils.ExceptionUtils;
+import org.apache.rocketmq.common.utils.FutureUtils;
import org.apache.rocketmq.common.utils.NetworkUtil;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.common.channel.ChannelHelper;
-import org.apache.rocketmq.common.utils.ExceptionUtils;
-import org.apache.rocketmq.common.utils.FutureUtils;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.processor.channel.ChannelExtendAttributeGetter;
import org.apache.rocketmq.proxy.processor.channel.ChannelProtocolType;
@@ -58,6 +55,10 @@ import org.apache.rocketmq.remoting.protocol.header.ConsumeMessageDirectlyResult
import org.apache.rocketmq.remoting.protocol.header.GetConsumerRunningInfoRequestHeader;
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
+import java.time.Duration;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
public class RemotingChannel extends ProxyChannel implements RemoteChannelConverter, ChannelExtendAttributeGetter {
private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
private static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis();
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java
index 6c19edf2f8..05eb672618 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java
@@ -17,35 +17,36 @@
package org.apache.rocketmq.proxy.service.sysmessage;
-import com.alibaba.fastjson.JSON;
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageDecoder;
import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.common.utils.StartAndShutdown;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.proxy.common.ProxyException;
import org.apache.rocketmq.proxy.common.ProxyExceptionCode;
-import org.apache.rocketmq.common.utils.StartAndShutdown;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.proxy.service.admin.AdminService;
-import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue;
import org.apache.rocketmq.proxy.service.route.TopicRouteService;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeader;
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+
public abstract class AbstractSystemMessageSyncer implements StartAndShutdown, MessageListenerConcurrently {
protected static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
protected final TopicRouteService topicRouteService;
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
index fee3ea87d2..e063d79707 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
@@ -17,21 +17,15 @@
package org.apache.rocketmq.proxy.service.sysmessage;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import io.netty.channel.Channel;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.broker.client.ConsumerGroupEvent;
import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener;
import org.apache.rocketmq.broker.client.ConsumerManager;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.thread.ThreadPoolMonitor;
@@ -40,13 +34,20 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.proxy.processor.channel.RemoteChannel;
import org.apache.rocketmq.proxy.service.admin.AdminService;
-import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
import org.apache.rocketmq.proxy.service.route.TopicRouteService;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
public class HeartbeatSyncer extends AbstractSystemMessageSyncer {
protected ThreadPoolExecutor threadPoolExecutor;
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
index 74803609ba..2caa4e37e9 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
@@ -21,6 +21,8 @@ import org.apache.rocketmq.proxy.ProxyMode;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
public class ConfigurationManagerTest extends InitConfigTest {
@@ -44,4 +46,12 @@ public class ConfigurationManagerTest extends InitConfigTest {
assertThat(ConfigurationManager.getProxyConfig()).isNotNull();
}
+ @Test
+ public void testFormatProxyConfig() {
+ String actual = ConfigurationManager.formatProxyConfig();
+ assertNotNull(actual);
+ ProxyConfig expected = ConfigurationManager.getProxyConfig();
+ assertTrue(actual.contains(expected.getProxyMode()));
+ assertTrue(actual.contains(expected.getProxyName()));
+ }
}
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationTest.java
similarity index 50%
copy from proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
copy to proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationTest.java
index 74803609ba..72b7eae6fa 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationTest.java
@@ -17,31 +17,30 @@
package org.apache.rocketmq.proxy.config;
-import org.apache.rocketmq.proxy.ProxyMode;
+import org.apache.rocketmq.auth.config.AuthConfig;
+import org.junit.Before;
import org.junit.Test;
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.spy;
-public class ConfigurationManagerTest extends InitConfigTest {
+public class ConfigurationTest {
- @Test
- public void testIntConfig() {
- assertThat(ConfigurationManager.getProxyConfig()).isNotNull();
- assertThat(ConfigurationManager.getProxyConfig().getProxyMode()).isEqualToIgnoringCase(ProxyMode.CLUSTER.toString());
+ private Configuration configuration;
- String brokerConfig = ConfigurationManager.getProxyConfig().getBrokerConfigPath();
- assertThat(brokerConfig).isEqualTo(ConfigurationManager.getProxyHome() + "/conf/broker.conf");
+ @Before
+ public void init() {
+ configuration = spy(new Configuration());
}
@Test
- public void testGetProxyHome() {
- // test configured proxy home
- assertThat(ConfigurationManager.getProxyHome()).isIn(mockProxyHome, "./");
- }
+ public void testInit() throws Exception {
+ configuration.init();
- @Test
- public void testGetProxyConfig() {
- assertThat(ConfigurationManager.getProxyConfig()).isNotNull();
- }
+ ProxyConfig loadedProxyConfig = configuration.getProxyConfig();
+ assertNotNull(loadedProxyConfig);
-}
+ AuthConfig loadedAuthConfig = configuration.getAuthConfig();
+ assertNotNull(loadedAuthConfig);
+ }
+}
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivityTest.java
new file mode 100644
index 0000000000..d956da52a1
--- /dev/null
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivityTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.proxy.remoting.activity;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.proxy.common.ProxyContext;
+import org.apache.rocketmq.proxy.config.ConfigurationManager;
+import org.apache.rocketmq.proxy.processor.MessagingProcessor;
+import org.apache.rocketmq.proxy.remoting.pipeline.RequestPipeline;
+import org.apache.rocketmq.proxy.service.channel.SimpleChannel;
+import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext;
+import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.RequestCode;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
+import org.apache.rocketmq.remoting.protocol.route.BrokerData;
+import org.apache.rocketmq.remoting.protocol.route.QueueData;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GetTopicRouteActivityTest {
+
+ @Mock
+ private RequestPipeline requestPipeline;
+
+ @Mock
+ private MessagingProcessor messagingProcessor;
+
+ private GetTopicRouteActivity getTopicRouteActivity;
+
+ private ChannelHandlerContext ctx;
+
+ private ProxyContext context;
+
+ @Before
+ public void setup() throws Exception {
+ getTopicRouteActivity = new GetTopicRouteActivity(requestPipeline, messagingProcessor);
+
+ ConfigurationManager.initEnv();
+ ConfigurationManager.intConfig();
+
+ Channel channel = new SimpleChannel(null, "0.0.0.0:0", "1.1.1.1:1");
+ ctx = new SimpleChannelHandlerContext(channel);
+
+ context = ProxyContext.create();
+ }
+
+ @Test
+ public void testProcessRequest0_HighVersion_SerializeWithFeatures() throws Exception {
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+ request.setVersion(MQVersion.Version.V4_9_4.ordinal());
+
+ GetRouteInfoRequestHeader header = new GetRouteInfoRequestHeader();
+ header.setTopic("TestTopic");
+ header.setAcceptStandardJsonOnly(false);
+ request.writeCustomHeader(header);
+
+ TopicRouteData topicRouteData = prepareTopicRouteData();
+
+ TopicRouteData spyTopicRouteData = Mockito.spy(topicRouteData);
+
+ ProxyTopicRouteData proxyTopicRouteData = mock(ProxyTopicRouteData.class);
+ when(proxyTopicRouteData.buildTopicRouteData()).thenReturn(spyTopicRouteData);
+ when(messagingProcessor.getTopicRouteDataForProxy(any(ProxyContext.class), anyList(), any()))
+ .thenReturn(proxyTopicRouteData);
+
+ RemotingCommand response = getTopicRouteActivity.processRequest0(ctx, request, context);
+
+ assertNotNull(response);
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+
+ verify(spyTopicRouteData).encode(
+ JSONWriter.Feature.BrowserCompatible,
+ JSONWriter.Feature.MapSortField
+ );
+
+ TopicRouteData deserializedData = JSON.parseObject(response.getBody(), TopicRouteData.class);
+ assertEquals(topicRouteData.getOrderTopicConf(), deserializedData.getOrderTopicConf());
+ assertEquals(topicRouteData.getQueueDatas().size(), deserializedData.getQueueDatas().size());
+ }
+
+ @Test
+ public void testProcessRequest0_LowVersion_StandardJsonOnly_SerializeWithFeatures() throws Exception {
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+ request.setVersion(MQVersion.Version.V4_9_3.ordinal());
+
+ GetRouteInfoRequestHeader header = new GetRouteInfoRequestHeader();
+ header.setTopic("TestTopic");
+ header.setAcceptStandardJsonOnly(true);
+ request.writeCustomHeader(header);
+
+ TopicRouteData topicRouteData = prepareTopicRouteData();
+
+ TopicRouteData spyTopicRouteData = Mockito.spy(topicRouteData);
+
+ ProxyTopicRouteData proxyTopicRouteData = mock(ProxyTopicRouteData.class);
+ when(proxyTopicRouteData.buildTopicRouteData()).thenReturn(spyTopicRouteData);
+ when(messagingProcessor.getTopicRouteDataForProxy(any(ProxyContext.class), anyList(), any()))
+ .thenReturn(proxyTopicRouteData);
+
+ RemotingCommand response = getTopicRouteActivity.processRequest0(ctx, request, context);
+
+ assertNotNull(response);
+ assertEquals(ResponseCode.SUCCESS, response.getCode());
+
+ verify(spyTopicRouteData).encode();
+ }
+
+ private TopicRouteData prepareTopicRouteData() {
+ TopicRouteData result = new TopicRouteData();
+ result.setOrderTopicConf("orderTopicConf");
+
+ List<QueueData> queueDatas = new ArrayList<>();
+ QueueData queueData = new QueueData();
+ queueData.setBrokerName("broker-a");
+ queueData.setPerm(6);
+ queueData.setReadQueueNums(4);
+ queueData.setWriteQueueNums(4);
+ queueData.setTopicSysFlag(0);
+ queueDatas.add(queueData);
+ result.setQueueDatas(queueDatas);
+
+ List<BrokerData> brokerDatas = new ArrayList<>();
+ BrokerData brokerData = new BrokerData();
+ brokerData.setBrokerName("broker-a");
+ HashMap<Long, String> brokerAddrs = new HashMap<>();
+ brokerAddrs.put(0L, "127.0.0.1:10911");
+ brokerData.setBrokerAddrs(brokerAddrs);
+ brokerDatas.add(brokerData);
+ result.setBrokerDatas(brokerDatas);
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/remoting/BUILD.bazel b/remoting/BUILD.bazel
index 9f806be763..62273e5e9d 100644
--- a/remoting/BUILD.bazel
+++ b/remoting/BUILD.bazel
@@ -22,7 +22,7 @@ java_library(
visibility = ["//visibility:public"],
deps = [
"//common",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_google_guava_guava",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_squareup_okio_okio_jvm",
@@ -51,7 +51,9 @@ java_library(
":remoting",
"//common",
"//:test_deps",
+ "@maven//:org_objenesis_objenesis",
"@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_google_code_gson_gson",
"@maven//:com_google_guava_guava",
"@maven//:com_google_code_findbugs_jsr305",
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
index 7ed977d99c..e39967e3f8 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
@@ -16,8 +16,8 @@
*/
package org.apache.rocketmq.remoting.netty;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
import com.google.common.base.Stopwatch;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
@@ -46,6 +46,28 @@ import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.common.Pair;
+import org.apache.rocketmq.common.ThreadFactoryImpl;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.FutureUtils;
+import org.apache.rocketmq.common.utils.NetworkUtil;
+import org.apache.rocketmq.common.utils.ThreadUtils;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.RemotingClient;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.RequestCode;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.proxy.SocksProxyConfig;
+
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
@@ -70,27 +92,6 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.rocketmq.common.Pair;
-import org.apache.rocketmq.common.ThreadFactoryImpl;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.utils.FutureUtils;
-import org.apache.rocketmq.common.utils.NetworkUtil;
-import org.apache.rocketmq.common.utils.ThreadUtils;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.ChannelEventListener;
-import org.apache.rocketmq.remoting.InvokeCallback;
-import org.apache.rocketmq.remoting.RemotingClient;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.exception.RemotingConnectException;
-import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
-import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.remoting.protocol.RequestCode;
-import org.apache.rocketmq.remoting.protocol.ResponseCode;
-import org.apache.rocketmq.remoting.proxy.SocksProxyConfig;
import static org.apache.rocketmq.remoting.common.RemotingHelper.convertChannelFutureToCompletableFuture;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java
index 8f53c0250b..3fe8eb2a0b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java
@@ -16,37 +16,46 @@
*/
package org.apache.rocketmq.remoting.protocol;
-import com.alibaba.fastjson.parser.DefaultJSONParser;
-import com.alibaba.fastjson.parser.JSONToken;
-import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
-import com.alibaba.fastjson.serializer.JSONSerializer;
-import com.alibaba.fastjson.serializer.ObjectSerializer;
-import com.alibaba.fastjson.serializer.SerializeWriter;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.JSONWriter;
+import com.alibaba.fastjson2.reader.ObjectReader;
+import com.alibaba.fastjson2.writer.ObjectWriter;
-import java.io.IOException;
import java.lang.reflect.Type;
+import java.util.Base64;
import java.util.BitSet;
-public class BitSetSerializerDeserializer implements ObjectSerializer, ObjectDeserializer {
+public class BitSetSerializerDeserializer implements ObjectReader<BitSet>, ObjectWriter<BitSet> {
@Override
- public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
- SerializeWriter out = serializer.out;
- out.writeByteArray(((BitSet) object).toByteArray());
+ public void write(JSONWriter writer, Object object, Object fieldName, Type fieldType, long features) {
+ if (object == null) {
+ writer.writeBase64(null);
+ } else {
+ writer.writeBase64(((BitSet) object).toByteArray());
+ }
}
- @SuppressWarnings("unchecked")
@Override
- public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
- byte[] bytes = parser.parseObject(byte[].class);
- if (bytes != null) {
- return (T) BitSet.valueOf(bytes);
+ public BitSet readObject(JSONReader reader, Type fieldType, Object fieldName, long features) {
+ if (reader.nextIfNull()) {
+ return null;
+ }
+ String base64 = reader.readString();
+ if (base64 == null || base64.isEmpty()) {
+ return null;
}
- return null;
+ byte[] bytes = Base64.getDecoder().decode(base64);
+ return BitSet.valueOf(bytes);
+ }
+
+ @Override
+ public long getFeatures() {
+ return 0L;
}
@Override
- public int getFastMatchToken() {
- return JSONToken.LITERAL_STRING;
+ public Class<BitSet> getObjectClass() {
+ return ObjectReader.super.getObjectClass();
}
}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java
index 9b2b0f07b4..e08a1627d1 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java
@@ -16,10 +16,20 @@
*/
package org.apache.rocketmq.remoting.protocol;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
import com.google.common.base.Stopwatch;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.common.BoundaryType;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.CommandCallback;
+import org.apache.rocketmq.remoting.CommandCustomHeader;
+import org.apache.rocketmq.remoting.annotation.CFNotNull;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -34,16 +44,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.rocketmq.common.BoundaryType;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.CommandCallback;
-import org.apache.rocketmq.remoting.CommandCustomHeader;
-import org.apache.rocketmq.remoting.annotation.CFNotNull;
-import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-
public class RemotingCommand {
public static final String SERIALIZE_TYPE_PROPERTY = "rocketmq.serialize.type";
public static final String SERIALIZE_TYPE_ENV = "ROCKETMQ_SERIALIZE_TYPE";
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 139a7043d8..c4e4da1468 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
@@ -16,8 +16,9 @@
*/
package org.apache.rocketmq.remoting.protocol;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
@@ -34,7 +35,10 @@ public abstract class RemotingSerializable {
}
public static String toJson(final Object obj, boolean prettyFormat) {
- return JSON.toJSONString(obj, prettyFormat);
+ if (prettyFormat) {
+ return JSON.toJSONString(obj, JSONWriter.Feature.PrettyFormat);
+ }
+ return JSON.toJSONString(obj);
}
public static <T> T decode(final byte[] data, Class<T> classOfT) {
@@ -74,7 +78,7 @@ public abstract class RemotingSerializable {
* @param features Features to apply
* @return serialized data.
*/
- public byte[] encode(SerializerFeature...features) {
+ public byte[] encode(JSONWriter.Feature... features) {
final String json = JSON.toJSONString(this, features);
return json.getBytes(CHARSET_UTF8);
}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java
index 82dcd8567e..6107bdce02 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.remoting.protocol.body;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
import org.apache.rocketmq.remoting.protocol.BitSetSerializerDeserializer;
import java.io.Serializable;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java
index 7312b70233..03920855bb 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java
@@ -17,7 +17,17 @@
package org.apache.rocketmq.remoting.protocol.body;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingInfo;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -30,15 +40,6 @@ import java.util.concurrent.ConcurrentMap;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
-import org.apache.rocketmq.common.MQVersion;
-import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.protocol.DataVersion;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
-import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingInfo;
public class RegisterBrokerBody extends RemotingSerializable {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java
index f7b4b9faef..d915bf0d16 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java
@@ -20,10 +20,12 @@
*/
package org.apache.rocketmq.remoting.protocol.heartbeat;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
import java.util.HashSet;
import java.util.Set;
-import com.alibaba.fastjson.JSON;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class HeartbeatData extends RemotingSerializable {
private String clientID;
@@ -79,7 +81,7 @@ public class HeartbeatData extends RemotingSerializable {
}
public int computeHeartbeatFingerprint() {
- HeartbeatData heartbeatDataCopy = JSON.parseObject(JSON.toJSONString(this), HeartbeatData.class);
+ HeartbeatData heartbeatDataCopy = JSON.parseObject(JSON.toJSONString(this, JSONWriter.Feature.ReferenceDetection), HeartbeatData.class);
for (ConsumerData consumerData : heartbeatDataCopy.getConsumerDataSet()) {
for (SubscriptionData subscriptionData : consumerData.getSubscriptionDataSet()) {
subscriptionData.setSubVersion(0L);
@@ -88,6 +90,6 @@ public class HeartbeatData extends RemotingSerializable {
heartbeatDataCopy.setWithoutSub(false);
heartbeatDataCopy.setHeartbeatFingerprint(0);
heartbeatDataCopy.setClientID("");
- return JSON.toJSONString(heartbeatDataCopy).hashCode();
+ return JSON.toJSONString(heartbeatDataCopy, JSONWriter.Feature.ReferenceDetection).hashCode();
}
}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java
index 59088fc42e..f110fac061 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java
@@ -20,10 +20,11 @@
*/
package org.apache.rocketmq.remoting.protocol.heartbeat;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
+import org.apache.rocketmq.common.filter.ExpressionType;
+
import java.util.HashSet;
import java.util.Set;
-import org.apache.rocketmq.common.filter.ExpressionType;
public class SubscriptionData implements Comparable<SubscriptionData> {
public final static String SUB_ALL = "*";
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java
index 14d5e53769..00bf2e9576 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java
@@ -17,7 +17,7 @@
package org.apache.rocketmq.remoting.protocol.subscription;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
import com.google.common.base.MoreObjects;
public class GroupRetryPolicy {
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableCompatTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableCompatTest.java
new file mode 100644
index 0000000000..35c1c7b891
--- /dev/null
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableCompatTest.java
@@ -0,0 +1,425 @@
+/*
+ * 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.remoting.protocol;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.JSON;
+import org.apache.rocketmq.remoting.protocol.body.BatchAck;
+import org.junit.Test;
+import org.objenesis.ObjenesisStd;
+import org.reflections.Reflections;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class RemotingSerializableCompatTest {
+
+ @Test
+ public void testCompatibilityCheck() {
+ Reflections reflections = new Reflections("org.apache.rocketmq.remoting.protocol");
+ Set<Class<? extends RemotingSerializable>> subTypes = reflections.getSubTypesOf(RemotingSerializable.class);
+
+ for (Class<? extends RemotingSerializable> clazz : subTypes) {
+ if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || clazz.getSimpleName().endsWith("Test")
+ || clazz.isAnonymousClass() || clazz.getName().contains("$")) {
+ continue;
+ }
+ try {
+ RemotingSerializable instance;
+ try {
+ instance = clazz.getDeclaredConstructor().newInstance();
+ } catch (NoSuchMethodException e) {
+ instance = allocateInstance(clazz);
+ }
+ fillDefaultFields(instance, clazz);
+ assertTrue(checkCompatible(instance, clazz));
+ } catch (Exception e) {
+ System.err.printf("Class %s: incompatible, error: %s\n", clazz.getName(), e.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void testCompatibilityCheckWithBitSet() {
+ BitSet bitSet = new BitSet();
+ bitSet.set(1);
+ bitSet.set(3);
+ bitSet.set(5);
+ String fastjson1Str = "{\"b\":\"Kg==\",\"c\":\"DEFAULT_CONSUMER\",\"it\":5000,\"pt\":1760694281326,\"q\":1,\"r\":\"0\",\"rq\":2,\"so\":100,\"t\":\"myTopic\"}";
+ BatchAck batchAck = JSON.parseObject(fastjson1Str, BatchAck.class);
+ assertEquals(bitSet, batchAck.getBitSet());
+ assertEquals("DEFAULT_CONSUMER", batchAck.getConsumerGroup());
+ assertEquals(5000, batchAck.getInvisibleTime());
+ assertEquals(1760694281326L, batchAck.getPopTime());
+ assertEquals(1, batchAck.getQueueId());
+ assertEquals("0", batchAck.getRetry());
+ assertEquals(2, batchAck.getReviveQueueId());
+ assertEquals(100, batchAck.getStartOffset());
+ assertEquals("myTopic", batchAck.getTopic());
+ }
+
+ private void fillDefaultFields(final Object obj, final Class<?> clazz) throws Exception {
+ if (null == clazz || clazz == Object.class) {
+ return;
+ }
+ for (Field field : clazz.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+ field.setAccessible(true);
+ Class<?> type = field.getType();
+
+ if (type.isArray()) {
+ Class<?> componentType = type.getComponentType();
+ Object arr = Array.newInstance(componentType, 1);
+ Object element = createElementOrDefault(componentType);
+ if (element != null) {
+ Array.set(arr, 0, element);
+ }
+ field.set(obj, arr);
+ } else if (Properties.class.isAssignableFrom(type)) {
+ field.set(obj, new Properties());
+ } else if (type.isEnum()) {
+ Object[] enumConstants = type.getEnumConstants();
+ if (enumConstants != null && enumConstants.length > 0) {
+ field.set(obj, enumConstants[0]);
+ }
+ } else if (ConcurrentHashMap.KeySetView.class.isAssignableFrom(type)) {
+ field.set(obj, ConcurrentHashMap.newKeySet());
+ } else if (ConcurrentHashMap.class.isAssignableFrom(type) || ConcurrentMap.class.isAssignableFrom(type)) {
+ field.set(obj, new ConcurrentHashMap<>());
+ } else if (Set.class.isAssignableFrom(type)) {
+ Set<Object> set = type.isInterface() ? new HashSet<>() : (Set<Object>) type.getDeclaredConstructor().newInstance();
+ Class<?> genericType = getFirstGenericType(field);
+ Object element = createElementOrDefault(genericType);
+ if (element != null)
+ set.add(element);
+ field.set(obj, set);
+ } else if (List.class.isAssignableFrom(type)) {
+ List<Object> list = new ArrayList<>();
+ Class<?> genericType = getFirstGenericType(field);
+ Object element = createElementOrDefault(genericType);
+ if (null != element) {
+ list.add(element);
+ }
+ field.set(obj, list);
+ } else if (Map.class.isAssignableFrom(type)) {
+ Map<Object, Object> map = type.isInterface() ? new HashMap<>() : (Map<Object, Object>) type.getDeclaredConstructor().newInstance();
+ Class<?> keyType = getGenericType(field, 0);
+ Class<?> valueType = getGenericType(field, 1);
+ Object key = createElementOrDefault(keyType);
+ Object value = createElementOrDefault(valueType);
+ if (null != key && null != value) {
+ map.put(key, value);
+ }
+ field.set(obj, map);
+ } else if (type == AtomicLong.class) {
+ field.set(obj, new AtomicLong(1));
+ } else {
+ Object value = getDefaultValue(type);
+ if (null != value) {
+ field.set(obj, value);
+ } else if (!type.isPrimitive() && !type.getName().startsWith("java.")) {
+ Object subObj;
+ try {
+ subObj = type.getDeclaredConstructor().newInstance();
+ } catch (NoSuchMethodException e) {
+ subObj = allocateInstance(type);
+ }
+ fillDefaultFields(subObj, type);
+ field.set(obj, subObj);
+ }
+ }
+ }
+ fillDefaultFields(obj, clazz.getSuperclass());
+ }
+
+ private Object createElementOrDefault(final Class<?> type) throws Exception {
+ if (null == type) {
+ return null;
+ }
+ Object value = getDefaultValue(type);
+ if (null != value) {
+ return value;
+ }
+ if (type.isEnum()) {
+ Object[] enumConstants = type.getEnumConstants();
+ if (null != enumConstants && enumConstants.length > 0) {
+ return enumConstants[0];
+ }
+ return null;
+ }
+ if (type.isArray()) {
+ Class<?> componentType = type.getComponentType();
+ Object arr = Array.newInstance(componentType, 1);
+ Object element = createElementOrDefault(componentType);
+ if (null != element) {
+ Array.set(arr, 0, element);
+ }
+ return arr;
+ }
+ if (!type.isPrimitive()) {
+ Object obj;
+ try {
+ obj = type.getDeclaredConstructor().newInstance();
+ } catch (NoSuchMethodException e) {
+ obj = allocateInstance(type);
+ }
+ fillDefaultFields(obj, type);
+ return obj;
+ }
+ return null;
+ }
+
+ private Class<?> getFirstGenericType(final Field field) {
+ return getGenericType(field, 0);
+ }
+
+ private Class<?> getGenericType(final Field field, final int index) {
+ try {
+ java.lang.reflect.Type genericType = field.getGenericType();
+ if (genericType instanceof java.lang.reflect.ParameterizedType) {
+ java.lang.reflect.Type[] types = ((java.lang.reflect.ParameterizedType) genericType).getActualTypeArguments();
+ if (types.length > index && types[index] instanceof Class) {
+ return (Class<?>) types[index];
+ }
+ }
+ } catch (Exception ignored) {
+ }
+ return null;
+ }
+
+ private Object getDefaultValue(final Class<?> type) {
+ if (null == type) {
+ return null;
+ }
+ if (type == boolean.class || type == Boolean.class) {
+ return false;
+ }
+ if (type == byte.class || type == Byte.class) {
+ return (byte) 1;
+ }
+ if (type == short.class || type == Short.class) {
+ return (short) 1;
+ }
+ if (type == int.class || type == Integer.class) {
+ return 1;
+ }
+ if (type == long.class || type == Long.class) {
+ return 1L;
+ }
+ if (type == float.class || type == Float.class) {
+ return 1f;
+ }
+ if (type == double.class || type == Double.class) {
+ return 1d;
+ }
+ if (type == char.class || type == Character.class) {
+ return '\0';
+ }
+ if (type == String.class) {
+ return "test";
+ }
+ return null;
+ }
+
+ private boolean checkCompatible(final Object original, final Object deserialized, final String path, final Map<Object, Object> visited) {
+ if (null == original && null == deserialized) {
+ return true;
+ }
+ if (null == original || null == deserialized) {
+ System.err.printf("Objects at %s incompatible: one is null\n", path);
+ return false;
+ }
+
+ if (!isPrimitiveOrWrapper(original.getClass())) {
+ if (visited.containsKey(original)) {
+ return true;
+ }
+ visited.put(original, deserialized);
+ }
+
+ Class<?> clazz = original.getClass();
+ boolean result = true;
+ for (Field field : clazz.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+ JSONField jsonField = field.getAnnotation(JSONField.class);
+ if (null != jsonField && !jsonField.serialize()) {
+ continue;
+ }
+ if ("hash".equals(field.getName()) || "serialVersionUID".equals(field.getName())) {
+ continue;
+ }
+
+ field.setAccessible(true);
+ try {
+ Object v1 = field.get(original);
+ Object v2 = field.get(deserialized);
+ String fieldPath = path + "." + field.getName();
+
+ if (null == v1 && null == v2) {
+ continue;
+ }
+ if (v1 instanceof Random && v2 instanceof Random) {
+ continue;
+ }
+ if (v1 instanceof AtomicLong && v2 instanceof AtomicLong) {
+ if (((AtomicLong) v1).get() != ((AtomicLong) v2).get()) {
+ result = false;
+ System.err.printf("Field %s incompatible: original=%s, deserialized=%s\n", fieldPath, v1, v2);
+ }
+ continue;
+ }
+ if (v1 instanceof Set && v2 instanceof Set) {
+ Set<?> s1 = (Set<?>) v1, s2 = (Set<?>) v2;
+ if (s1.size() != s2.size()) {
+ result = false;
+ System.err.printf("Field %s incompatible: set size original=%d, deserialized=%d\n", fieldPath, s1.size(), s2.size());
+ } else if (!s1.isEmpty()) {
+ List<?> list1 = new ArrayList<>(s1);
+ List<?> list2 = new ArrayList<>(s2);
+ if (new HashSet<>(list1).equals(new HashSet<>(list2))) {
+ continue;
+ }
+ boolean elementsCompatible = true;
+ for (Object e1 : list1) {
+ boolean foundMatch = false;
+ for (Object e2 : list2) {
+ if (checkCompatible(e1, e2, fieldPath + ".element", new HashMap<>(visited))) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (!foundMatch) {
+ elementsCompatible = false;
+ break;
+ }
+ }
+ if (!elementsCompatible) {
+ result = false;
+ System.err.printf("Field %s incompatible: sets have different elements\n", fieldPath);
+ }
+ }
+ continue;
+ }
+ if (v1 instanceof List && v2 instanceof List) {
+ List<?> l1 = (List<?>) v1, l2 = (List<?>) v2;
+ if (l1.size() != l2.size()) {
+ result = false;
+ System.err.printf("Field %s incompatible: list size original=%d, deserialized=%d\n", fieldPath, l1.size(), l2.size());
+ } else {
+ for (int i = 0; i < l1.size(); i++) {
+ Object e1 = l1.get(i);
+ Object e2 = l2.get(i);
+ if (!checkCompatible(e1, e2, fieldPath + "[" + i + "]", new HashMap<>(visited))) {
+ result = false;
+ }
+ }
+ }
+ continue;
+ }
+ if (v1 instanceof Map && v2 instanceof Map) {
+ Map<?, ?> m1 = (Map<?, ?>) v1, m2 = (Map<?, ?>) v2;
+ if (!m1.keySet().equals(m2.keySet())) {
+ result = false;
+ System.err.printf("Field %s incompatible: map keys original=%s, deserialized=%s\n", fieldPath, m1.keySet(), m2.keySet());
+ } else {
+ for (Object key : m1.keySet()) {
+ Object val1 = m1.get(key), val2 = m2.get(key);
+ if (val1 != null && val2 != null) {
+ if (!checkCompatible(val1, val2, fieldPath + "[" + key + "]", new HashMap<>(visited))) {
+ result = false;
+ }
+ } else if (val1 != val2) {
+ result = false;
+ System.err.printf("Field %s key %s incompatible: original=%s, deserialized=%s\n",
+ fieldPath, key, val1, val2);
+ }
+ }
+ }
+ continue;
+ }
+ Class<?> type = field.getType();
+ if (null != v1 && null != v2 && !type.isPrimitive() && !type.getName().startsWith("java.")) {
+ if (!checkCompatible(v1, v2, fieldPath, new HashMap<>(visited))) {
+ result = false;
+ }
+ continue;
+ }
+ if (null == v1 || null == v2 || !v1.equals(v2)) {
+ result = false;
+ System.err.printf("Field %s incompatible: original=%s, deserialized=%s\n", fieldPath, v1, v2);
+ }
+ } catch (Exception e) {
+ result = false;
+ System.err.printf("Field %s error: %s\n", path + "." + field.getName(), e.getMessage());
+ }
+ }
+ if (result) {
+ System.out.printf("Class %s compatible\n", path);
+ }
+ return result;
+ }
+
+ private boolean isPrimitiveOrWrapper(final Class<?> clazz) {
+ return clazz.isPrimitive() ||
+ clazz == String.class ||
+ clazz == Boolean.class ||
+ clazz == Character.class ||
+ clazz == Byte.class ||
+ clazz == Short.class ||
+ clazz == Integer.class ||
+ clazz == Long.class ||
+ clazz == Float.class ||
+ clazz == Double.class;
+ }
+
+ private boolean checkCompatible(final Object original, final Class<?> clazz) {
+ String json = com.alibaba.fastjson.JSON.toJSONString(original);
+ Object deserialized;
+ try {
+ deserialized = com.alibaba.fastjson2.JSON.parseObject(json, clazz);
+ } catch (Exception e) {
+ System.err.printf("Deserialization failed for %s: %s\n", clazz.getName(), e.getMessage());
+ return false;
+ }
+ return checkCompatible(original, deserialized, clazz.getSimpleName(), new HashMap<>());
+ }
+
+ private <T> T allocateInstance(final Class<T> clazz) {
+ return new ObjenesisStd().newInstance(clazz);
+ }
+}
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java
index 6bd80217da..e2655fd35d 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.remoting.protocol;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSONWriter;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.TypeAdapter;
@@ -105,8 +105,7 @@ public class RemotingSerializableTest {
}
Foo foo = new Foo();
String invalid = new String(foo.encode(), Charset.defaultCharset());
- String valid = new String(foo.encode(SerializerFeature.BrowserCompatible, SerializerFeature.QuoteFieldNames,
- SerializerFeature.MapSortField), Charset.defaultCharset());
+ String valid = new String(foo.encode(JSONWriter.Feature.BrowserCompatible, JSONWriter.Feature.MapSortField), Charset.defaultCharset());
Gson gson = new Gson();
final TypeAdapter<JsonElement> strictAdapter = gson.getAdapter(JsonElement.class);
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java
index 427a132d64..81e8f13394 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.remoting.protocol.body;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import org.apache.rocketmq.common.MixAll;
import org.junit.Test;
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java
index 6b8a1392f5..7bb7b8ca7e 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java
@@ -17,15 +17,15 @@
package org.apache.rocketmq.remoting.protocol.statictopic;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.ImmutableList;
-import java.util.Map;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
import org.junit.Assert;
import org.junit.Test;
+import java.util.Map;
+
public class TopicQueueMappingTest {
@Test
@@ -59,7 +59,6 @@ public class TopicQueueMappingTest {
Assert.assertTrue(mappingDetailMap.containsKey("currIdMap"));
Assert.assertEquals(8, mappingDetailMap.size());
Assert.assertEquals(1, ((JSONObject) mappingDetailMap.get("hostedQueues")).size());
- Assert.assertEquals(1, ((JSONArray)((JSONObject) mappingDetailMap.get("hostedQueues")).get("0")).size());
}
{
TopicQueueMappingDetail mappingDetailFromJson = RemotingSerializable.decode(mappingDetailJson.getBytes(), TopicQueueMappingDetail.class);
@@ -69,9 +68,4 @@ public class TopicQueueMappingTest {
Assert.assertEquals(mappingDetailJson, RemotingSerializable.toJson(mappingDetailFromJson, false));
}
}
-
- @Test
- public void test() {
-
- }
}
diff --git a/srvutil/BUILD.bazel b/srvutil/BUILD.bazel
index 699d78bcd9..8909409810 100644
--- a/srvutil/BUILD.bazel
+++ b/srvutil/BUILD.bazel
@@ -26,7 +26,6 @@ java_library(
"@maven//:commons_validator_commons_validator",
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
- "@maven//:com_alibaba_fastjson",
"@maven//:io_netty_netty_all",
"@maven//:commons_cli_commons_cli",
"@maven//:com_googlecode_concurrentlinkedhashmap_concurrentlinkedhashmap_lru",
diff --git a/store/BUILD.bazel b/store/BUILD.bazel
index de98657b22..8986c9b236 100644
--- a/store/BUILD.bazel
+++ b/store/BUILD.bazel
@@ -23,7 +23,6 @@ java_library(
deps = [
"//common",
"//remoting",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_conversantmedia_disruptor",
"@maven//:com_google_guava_guava",
@@ -58,7 +57,7 @@ java_library(
"//:test_deps",
"//common",
"//remoting",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_conversantmedia_disruptor",
"@maven//:io_openmessaging_storage_dledger",
"@maven//:org_apache_commons_commons_lang3",
diff --git a/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java b/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java
index 3e65c104b1..f722c123ea 100644
--- a/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java
+++ b/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.store.pop;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
public class AckMsg {
diff --git a/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java b/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java
index 991a1f085d..f2689dfdfb 100644
--- a/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java
+++ b/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java
@@ -16,7 +16,8 @@
*/
package org.apache.rocketmq.store.pop;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
+
import java.util.ArrayList;
import java.util.List;
diff --git a/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java b/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java
index 38e0a20752..e3587aa28c 100644
--- a/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java
+++ b/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java
@@ -16,7 +16,8 @@
*/
package org.apache.rocketmq.store.pop;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
+
import java.util.ArrayList;
import java.util.List;
@@ -35,7 +36,6 @@ public class PopCheckPoint implements Comparable<PopCheckPoint> {
private int queueId;
@JSONField(name = "t")
private String topic;
- @JSONField(name = "c")
private String cid;
@JSONField(name = "ro")
private long reviveOffset;
@@ -114,10 +114,12 @@ public class PopCheckPoint implements Comparable<PopCheckPoint> {
this.topic = topic;
}
+ @JSONField(name = "c")
public String getCId() {
return cid;
}
+ @JSONField(name = "c")
public void setCId(String cid) {
this.cid = cid;
}
diff --git a/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java b/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java
index c8c3202a78..5de1664cdb 100644
--- a/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java
+++ b/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java
@@ -17,7 +17,7 @@
package org.apache.rocketmq.store.queue;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import com.google.common.annotations.VisibleForTesting;
import java.util.Arrays;
import java.util.LinkedList;
diff --git a/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java b/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java
index ba7240414a..338a62252f 100644
--- a/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java
+++ b/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java
@@ -16,9 +16,21 @@
*/
package org.apache.rocketmq.store.timer;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import org.apache.rocketmq.common.ConfigManager;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.message.MessageConst;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
import java.io.File;
+import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.io.Writer;
@@ -36,16 +48,6 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import org.apache.rocketmq.common.ConfigManager;
-import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.message.MessageConst;
-import org.apache.rocketmq.common.message.MessageExt;
-import org.apache.rocketmq.common.topic.TopicValidator;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.protocol.DataVersion;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class TimerMetrics extends ConfigManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -135,11 +137,11 @@ public class TimerMetrics extends ConfigManager {
return timingCount;
}
- protected void write0(Writer writer) {
+ protected void write0(Writer writer) throws IOException {
TimerMetricsSerializeWrapper wrapper = new TimerMetricsSerializeWrapper();
wrapper.setTimingCount(timingCount);
wrapper.setDataVersion(dataVersion);
- JSON.writeJSONString(writer, wrapper, SerializerFeature.BrowserCompatible);
+ writer.write(JSON.toJSONString(wrapper, JSONWriter.Feature.BrowserCompatible));
}
@Override public String encode() {
@@ -152,7 +154,7 @@ public class TimerMetrics extends ConfigManager {
@Override public void decode(String jsonString) {
if (jsonString != null) {
- TimerMetricsSerializeWrapper timerMetricsSerializeWrapper = TimerMetricsSerializeWrapper.fromJson(jsonString, TimerMetricsSerializeWrapper.class);
+ TimerMetricsSerializeWrapper timerMetricsSerializeWrapper = TimerMetricsSerializeWrapper.fromJson(jsonString, TimerMetricsSerializeWrapper.class);
if (timerMetricsSerializeWrapper != null) {
this.timingCount.putAll(timerMetricsSerializeWrapper.getTimingCount());
this.dataVersion.assignNewOne(timerMetricsSerializeWrapper.getDataVersion());
@@ -179,7 +181,7 @@ public class TimerMetrics extends ConfigManager {
while (iterator.hasNext()) {
Map.Entry<String, Metric> entry = iterator.next();
final String topic = entry.getKey();
- if (topic.startsWith(TopicValidator.SYSTEM_TOPIC_PREFIX) || topic.startsWith(MixAll.LMQ_PREFIX)) {
+ if (topic.startsWith(TopicValidator.SYSTEM_TOPIC_PREFIX) || topic.startsWith(MixAll.LMQ_PREFIX)) {
continue;
}
if (topics.contains(topic)) {
diff --git a/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java b/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java
index b5a3ff6381..13df028e83 100644
--- a/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java
+++ b/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java
@@ -17,7 +17,7 @@
package org.apache.rocketmq.store.pop;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import org.junit.Assert;
import org.junit.Test;
diff --git a/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java b/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java
index 4bcfcf18be..0a1bc714cf 100644
--- a/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java
+++ b/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java
@@ -17,7 +17,7 @@
package org.apache.rocketmq.store.pop;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import org.junit.Assert;
import org.junit.Test;
diff --git a/test/BUILD.bazel b/test/BUILD.bazel
index a8a7a9d8bb..d34456f355 100644
--- a/test/BUILD.bazel
+++ b/test/BUILD.bazel
@@ -28,7 +28,6 @@ java_library(
"//tools",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:ch_qos_logback_logback_core",
- "@maven//:com_alibaba_fastjson",
"@maven//:com_github_luben_zstd_jni",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java_util",
diff --git a/tieredstore/BUILD.bazel b/tieredstore/BUILD.bazel
index 8822280ff8..0a94302086 100644
--- a/tieredstore/BUILD.bazel
+++ b/tieredstore/BUILD.bazel
@@ -39,7 +39,7 @@ java_library(
"@maven//:io_opentelemetry_opentelemetry_exporter_logging_otlp",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:org_apache_tomcat_annotations_api",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:org_apache_rocketmq_rocketmq_rocksdb",
"@maven//:commons_collections_commons_collections",
"@maven//:org_slf4j_slf4j_api",
@@ -57,7 +57,7 @@ java_library(
"//common",
"//remoting",
"//store",
- "@maven//:com_alibaba_fastjson",
+ "@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:commons_io_commons_io",
"@maven//:io_opentelemetry_opentelemetry_api",
"@maven//:io_opentelemetry_opentelemetry_context",
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java
index b0e4dd6e3b..a7505b4bf4 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.tieredstore.file;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import com.google.common.annotations.VisibleForTesting;
import java.nio.ByteBuffer;
import java.util.ArrayList;
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java
index 09500bf6da..eb726543cf 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java
@@ -16,17 +16,9 @@
*/
package org.apache.rocketmq.tieredstore.metadata;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import com.google.common.annotations.VisibleForTesting;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Consumer;
import org.apache.rocketmq.common.ConfigManager;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
@@ -36,6 +28,15 @@ import org.apache.rocketmq.tieredstore.metadata.entity.FileSegmentMetadata;
import org.apache.rocketmq.tieredstore.metadata.entity.QueueMetadata;
import org.apache.rocketmq.tieredstore.metadata.entity.TopicMetadata;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
+
public class DefaultMetadataStore extends ConfigManager implements MetadataStore {
private static final int DEFAULT_CAPACITY = 1024;
@@ -80,12 +81,9 @@ public class DefaultMetadataStore extends ConfigManager implements MetadataStore
dataWrapper.setIndexFileSegmentTable(new ConcurrentHashMap<>(indexFileSegmentTable));
if (prettyFormat) {
- return JSON.toJSONString(
- dataWrapper, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.PrettyFormat);
- } else {
- return JSON.toJSONString(
- dataWrapper, SerializerFeature.DisableCircularReferenceDetect);
+ return JSON.toJSONString(dataWrapper, JSONWriter.Feature.PrettyFormat);
}
+ return JSON.toJSONString(dataWrapper);
}
@Override
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java
index 4f988ca241..da2a0fd06c 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.tieredstore.metadata.entity;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
import java.util.Objects;
public class FileSegmentMetadata {
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java
index 6720f1d08a..3f976f037d 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.tieredstore.metadata.entity;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
import org.apache.rocketmq.common.message.MessageQueue;
public class QueueMetadata {
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java
index 80e5230e7a..72b994fc84 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.tieredstore.metadata.entity;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
public class TopicMetadata {
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
index ec6fa1eaac..a809a7a92e 100644
--- a/tools/BUILD.bazel
+++ b/tools/BUILD.bazel
@@ -29,7 +29,6 @@ java_library(
"@maven//:commons_validator_commons_validator",
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
- "@maven//:com_alibaba_fastjson",
"@maven//:io_netty_netty_all",
"@maven//:commons_cli_commons_cli",
"@maven//:org_slf4j_slf4j_api",
diff --git a/tools/pom.xml b/tools/pom.xml
index 8eea4977e6..1d63ded9b8 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -44,10 +44,6 @@
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-srvutil</artifactId>
</dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
index 948c4430d5..f2e1cda2bd 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.tools.admin;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.QueryResult;
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java
index 34b3ba7d30..76c111b95c 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java
@@ -16,13 +16,9 @@
*/
package org.apache.rocketmq.tools.command.broker;
-import java.io.UnsupportedEncodingException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -37,6 +33,12 @@ import org.apache.rocketmq.tools.command.CommandUtil;
import org.apache.rocketmq.tools.command.SubCommand;
import org.apache.rocketmq.tools.command.SubCommandException;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
public class GetColdDataFlowCtrInfoSubCommand implements SubCommand {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -116,7 +118,7 @@ public class GetColdDataFlowCtrInfoSubCommand implements SubCommand {
value.remove("createTimeMills");
});
- String formatStr = JSON.toJSONString(jsonObject, true);
+ String formatStr = JSON.toJSONString(jsonObject, JSONWriter.Feature.PrettyFormat);
System.out.printf(formatStr);
System.out.printf("%n");
}
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java
index b17da4de45..d4782a0684 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java
@@ -16,9 +16,7 @@
*/
package org.apache.rocketmq.tools.command.consumer;
-import com.alibaba.fastjson.JSON;
-import java.util.Map;
-import java.util.Set;
+import com.alibaba.fastjson2.JSON;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -32,6 +30,9 @@ import org.apache.rocketmq.tools.command.CommandUtil;
import org.apache.rocketmq.tools.command.SubCommand;
import org.apache.rocketmq.tools.command.SubCommandException;
+import java.util.Map;
+import java.util.Set;
+
public class UpdateSubGroupSubCommand implements SubCommand {
@Override
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java
index c3f96d5972..ebb1cf82ba 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java
@@ -16,15 +16,8 @@
*/
package org.apache.rocketmq.tools.command.export;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Arrays;
-import java.util.Properties;
-
-import com.alibaba.fastjson.JSON;
-
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -35,6 +28,13 @@ import org.apache.rocketmq.tools.command.CommandUtil;
import org.apache.rocketmq.tools.command.SubCommand;
import org.apache.rocketmq.tools.command.SubCommandException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
public class ExportConfigsCommand implements SubCommand {
@Override
public String commandName() {
@@ -98,7 +98,7 @@ public class ExportConfigsCommand implements SubCommand {
result.put("clusterScale", clusterScaleMap);
String path = filePath + "/configs.json";
- MixAll.string2FileNotSafe(JSON.toJSONString(result, true), path);
+ MixAll.string2FileNotSafe(JSON.toJSONString(result, JSONWriter.Feature.PrettyFormat), path);
System.out.printf("export %s success", path);
} catch (Exception e) {
throw new SubCommandException(this.getClass().getSimpleName() + " command failed", e);
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java
index 748f7b16e1..559936bcb8 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java
@@ -16,10 +16,8 @@
*/
package org.apache.rocketmq.tools.command.export;
-import com.alibaba.fastjson.JSON;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -35,6 +33,10 @@ import org.apache.rocketmq.tools.command.CommandUtil;
import org.apache.rocketmq.tools.command.SubCommand;
import org.apache.rocketmq.tools.command.SubCommandException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
public class ExportMetadataCommand implements SubCommand {
private static final String DEFAULT_FILE_PATH = "/tmp/rocketmq/export";
@@ -99,13 +101,13 @@ public class ExportMetadataCommand implements SubCommand {
filePath = filePath + "/topic.json";
TopicConfigSerializeWrapper topicConfigSerializeWrapper = defaultMQAdminExt.getUserTopicConfig(
brokerAddr, specialTopic, 10000L);
- MixAll.string2FileNotSafe(JSON.toJSONString(topicConfigSerializeWrapper, true), filePath);
+ MixAll.string2FileNotSafe(JSON.toJSONString(topicConfigSerializeWrapper, JSONWriter.Feature.PrettyFormat), filePath);
System.out.printf("export %s success", filePath);
} else if (commandLine.hasOption('g')) {
filePath = filePath + "/subscriptionGroup.json";
SubscriptionGroupWrapper subscriptionGroupWrapper = defaultMQAdminExt.getUserSubscriptionGroup(
brokerAddr, 10000L);
- MixAll.string2FileNotSafe(JSON.toJSONString(subscriptionGroupWrapper, true), filePath);
+ MixAll.string2FileNotSafe(JSON.toJSONString(subscriptionGroupWrapper, JSONWriter.Feature.PrettyFormat), filePath);
System.out.printf("export %s success", filePath);
}
} else if (commandLine.hasOption('c')) {
@@ -163,7 +165,7 @@ public class ExportMetadataCommand implements SubCommand {
exportPath = filePath + "/metadata.json";
}
result.put("exportTime", System.currentTimeMillis());
- MixAll.string2FileNotSafe(JSON.toJSONString(result, true), exportPath);
+ MixAll.string2FileNotSafe(JSON.toJSONString(result, JSONWriter.Feature.PrettyFormat), exportPath);
System.out.printf("export %s success%n", exportPath);
} else {
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java
index 438d17d668..1a3e5e5a6a 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java
@@ -17,11 +17,9 @@
package org.apache.rocketmq.tools.command.export;
-import com.alibaba.fastjson.JSONObject;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.BiConsumer;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -34,6 +32,11 @@ import org.apache.rocketmq.tools.command.SubCommand;
import org.apache.rocketmq.tools.command.SubCommandException;
import org.rocksdb.RocksIterator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiConsumer;
+
public class ExportMetadataInRocksDBCommand implements SubCommand {
private static final String TOPICS_JSON_CONFIG = "topics";
private static final String SUBSCRIPTION_GROUP_JSON_CONFIG = "subscriptionGroups";
@@ -118,8 +121,8 @@ public class ExportMetadataInRocksDBCommand implements SubCommand {
);
jsonConfig.put(configType.equalsIgnoreCase(TOPICS_JSON_CONFIG) ? "topicConfigTable" : "subscriptionGroupTable",
- (JSONObject) JSONObject.toJSON(configTable));
- final String jsonConfigStr = JSONObject.toJSONString(jsonConfig, true);
+ (JSONObject) JSON.toJSON(configTable));
+ final String jsonConfigStr = JSONObject.toJSONString(jsonConfig, JSONWriter.Feature.PrettyFormat);
System.out.print(jsonConfigStr + "\n");
} else {
AtomicLong count = new AtomicLong(0);
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java
index 5d8bb37ba0..1b7d5d44e3 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java
@@ -16,12 +16,8 @@
*/
package org.apache.rocketmq.tools.command.export;
-import com.alibaba.fastjson.JSON;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -47,6 +43,12 @@ import org.apache.rocketmq.tools.command.SubCommand;
import org.apache.rocketmq.tools.command.SubCommandException;
import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
public class ExportMetricsCommand implements SubCommand {
@Override
@@ -133,7 +135,7 @@ public class ExportMetricsCommand implements SubCommand {
result.put("evaluateReport", evaluateReportMap);
result.put("totalData", totalData);
- MixAll.string2FileNotSafe(JSON.toJSONString(result, true), path);
+ MixAll.string2FileNotSafe(JSON.toJSONString(result, JSONWriter.Feature.PrettyFormat), path);
System.out.printf("export %s success", path);
} catch (Exception e) {
throw new SubCommandException(this.getClass().getSimpleName() + " command failed", e);
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java
index 94899fce08..d65a04136b 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java
@@ -17,22 +17,8 @@
package org.apache.rocketmq.tools.command.metadata;
-import com.alibaba.fastjson.JSONObject;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicLong;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -49,6 +35,22 @@ import org.apache.rocketmq.tools.command.SubCommand;
import org.apache.rocketmq.tools.command.SubCommandException;
import org.rocksdb.RocksIterator;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+
public class RocksDBConfigToJsonCommand implements SubCommand {
@Override
@@ -136,10 +138,10 @@ public class RocksDBConfigToJsonCommand implements SubCommand {
if (commandLine.hasOption("jsonEnable") && "false".equalsIgnoreCase(commandLine.getOptionValue("jsonEnable").trim())) {
printConfigMapJsonDisable(configMap);
} else {
- System.out.print(JSONObject.toJSONString(configMap, true) + "\n");
+ System.out.print(JSONObject.toJSONString(configMap, JSONWriter.Feature.PrettyFormat) + "\n");
}
} else {
- String jsonString = JSONObject.toJSONString(configMap, true);
+ String jsonString = JSONObject.toJSONString(configMap, JSONWriter.Feature.PrettyFormat);
try {
MixAll.string2File(jsonString, exportFile);
} catch (IOException e) {
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
index 4902b8a881..24d9900b61 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
@@ -17,7 +17,8 @@
package org.apache.rocketmq.tools.command.queue;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
@@ -121,7 +122,7 @@ public class QueryConsumeQueueCommand implements SubCommand {
);
if (queryConsumeQueueResponseBody.getSubscriptionData() != null) {
- System.out.printf("Subscription data: \n%s\n", JSON.toJSONString(queryConsumeQueueResponseBody.getSubscriptionData(), true));
+ System.out.printf("Subscription data: \n%s\n", JSON.toJSONString(queryConsumeQueueResponseBody.getSubscriptionData(), JSONWriter.Feature.PrettyFormat));
System.out.print("======================================\n");
}
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImplTest.java b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImplTest.java
new file mode 100644
index 0000000000..c5ea051ab4
--- /dev/null
+++ b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImplTest.java
@@ -0,0 +1,825 @@
+/*
+ * 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.tools.admin;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.impl.MQAdminImpl;
+import org.apache.rocketmq.client.impl.MQClientAPIImpl;
+import org.apache.rocketmq.client.impl.factory.MQClientInstance;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.message.MessageQueue;
+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.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
+import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
+import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
+import org.apache.rocketmq.remoting.protocol.admin.TopicOffset;
+import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
+import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
+import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
+import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
+import org.apache.rocketmq.remoting.protocol.body.GroupList;
+import org.apache.rocketmq.remoting.protocol.body.QueueTimeSpan;
+import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
+import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
+import org.apache.rocketmq.remoting.protocol.body.TopicList;
+import org.apache.rocketmq.remoting.protocol.header.UpdateConsumerOffsetRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.UpdateGroupForbiddenRequestHeader;
+import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.protocol.route.BrokerData;
+import org.apache.rocketmq.remoting.protocol.route.QueueData;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import org.apache.rocketmq.remoting.protocol.subscription.GroupForbidden;
+import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.tools.admin.api.BrokerOperatorResult;
+import org.apache.rocketmq.tools.admin.api.MessageTrack;
+import org.apache.rocketmq.tools.admin.common.AdminToolResult;
+import org.apache.rocketmq.tools.admin.common.AdminToolsResultCodeEnum;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultMQAdminExtImplTest {
+
+ private DefaultMQAdminExtImpl defaultMQAdminExtImpl;
+
+ @Mock
+ private DefaultMQAdminExt defaultMQAdminExt;
+
+ @Mock
+ private MQClientInstance mqClientInstance;
+
+ @Mock
+ private MQClientAPIImpl mqClientAPIImpl;
+
+ @Mock
+ private MQAdminImpl mqAdminImpl;
+
+ private final String defaultTopic = "defaultTopic";
+
+ private final String defaultCluster = "cluster";
+
+ private final String defaultBroker = "broker1";
+
+ private final String defaultGroup = "consumerGroup";
+
+ private final String defaultBrokerAddr = "127.0.0.1:10911";
+
+ private final long timeoutMillis = 3000L;
+
+ private final String defaultMsgId = "AC1A43AC00002A9F00008F214319C26B";
+
+ @Before
+ public void init() throws IllegalAccessException, RemotingException, InterruptedException, MQClientException, MQBrokerException {
+ defaultMQAdminExtImpl = new DefaultMQAdminExtImpl(defaultMQAdminExt, timeoutMillis);
+ FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "mqClientInstance", mqClientInstance, true);
+ FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "mqClientInstance", mqClientInstance, true);
+ FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "threadPoolExecutor", Executors.newFixedThreadPool(1), true);
+ when(mqClientInstance.getMQClientAPIImpl()).thenReturn(mqClientAPIImpl);
+ when(mqClientInstance.getMQAdminImpl()).thenReturn(mqAdminImpl);
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(createTopicRouteData());
+ }
+
+ @Test
+ public void testExamineTopicStats() throws Exception {
+ TopicStatsTable topicStatsTable = mock(TopicStatsTable.class);
+ Map<MessageQueue, TopicOffset> offsetTable = new ConcurrentHashMap<>();
+ offsetTable.put(new MessageQueue(), new TopicOffset());
+ when(topicStatsTable.getOffsetTable()).thenReturn(offsetTable);
+ when(mqClientAPIImpl.getTopicStatsInfo(any(), any(), anyLong())).thenReturn(topicStatsTable);
+ TopicStatsTable actual = defaultMQAdminExtImpl.examineTopicStats(defaultTopic);
+ assertNotNull(actual);
+ assertEquals(offsetTable.size(), actual.getOffsetTable().size());
+ }
+
+ @Test
+ public void testExamineTopicStatsConcurrentTopicRouteDataNull() throws Exception {
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+ AdminToolResult<TopicStatsTable> actual = defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic);
+ assertNotNull(actual);
+ assertEquals(200, actual.getCode());
+ assertEquals(0, actual.getData().getOffsetTable().size());
+ }
+
+ @Test
+ public void testExamineTopicStatsConcurrentBrokerDataEmpty() throws Exception {
+ TopicRouteData topicRouteData = mock(TopicRouteData.class);
+ when(topicRouteData.getBrokerDatas()).thenReturn(new ArrayList<>());
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(topicRouteData);
+ AdminToolResult<TopicStatsTable> actual = defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic);
+ assertNotNull(actual);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+ assertEquals(0, actual.getData().getOffsetTable().size());
+ }
+
+ @Test
+ public void testExamineTopicStatsConcurrent() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ doAnswer(invocation -> {
+ latch.countDown();
+ return null;
+ }).when(mqClientAPIImpl).getTopicStatsInfo(any(), any(), anyLong());
+ latch.await(1000, TimeUnit.MILLISECONDS);
+ AdminToolResult<TopicStatsTable> actual = defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic);
+ assertNotNull(actual);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+ assertEquals(0, actual.getData().getOffsetTable().size());
+ }
+
+ @Test
+ public void testExamineTopicStatsConcurrentException() throws Exception {
+ doThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception")).when(mqClientAPIImpl).getTopicStatsInfo(any(), any(), anyLong());
+ assertNotNull(defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic));
+ }
+
+ @Test
+ public void testExamineConsumeStatsConcurrentTopicRouteInfoNotExist() throws Exception {
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+ AdminToolResult<ConsumeStats> result = defaultMQAdminExtImpl.examineConsumeStatsConcurrent(defaultGroup, defaultTopic);
+ assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), result.getCode());
+ }
+
+ @Test
+ public void testExamineConsumeStatsConcurrent() throws Exception {
+ AtomicInteger count = new AtomicInteger(0);
+ AtomicInteger success = new AtomicInteger(0);
+ AtomicInteger fail = new AtomicInteger(0);
+ CountDownLatch latch = new CountDownLatch(10);
+ ExecutorService executorService = Executors.newFixedThreadPool(10);
+ List<BrokerData> brokerDataList = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ BrokerData bd = new BrokerData();
+ bd.setBrokerName("brokerName" + i);
+ bd.setCluster(defaultCluster);
+ bd.setBrokerAddrs(createBrokerAddrs());
+ brokerDataList.add(bd);
+ }
+ TopicRouteData topicRouteData = new TopicRouteData();
+ topicRouteData.setBrokerDatas(brokerDataList);
+ for (int i = 0; i < 10; i++) {
+ executorService.submit(() -> {
+ try {
+ Thread.sleep(100);
+ if (count.incrementAndGet() % 2 == 0) {
+ success.incrementAndGet();
+ } else {
+ throw new RemotingException("Test Exception");
+ }
+ latch.countDown();
+ } catch (Exception e) {
+ fail.incrementAndGet();
+ }
+ });
+ }
+ latch.await(3000, TimeUnit.MILLISECONDS);
+ executorService.shutdown();
+ assertEquals(5, success.get());
+ assertEquals(5, fail.get());
+ assertEquals(10, count.get());
+ }
+
+ @Test
+ public void testExamineConsumeStatsConcurrentEmptyOffsetTable() throws Exception {
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(anyString(), anyLong())).thenReturn(createTopicRouteData());
+ when(mqClientAPIImpl.getConsumeStats(anyString(), anyString(), anyString(), anyLong())).thenReturn(new ConsumeStats());
+ AdminToolResult<ConsumeStats> actual = defaultMQAdminExtImpl.examineConsumeStatsConcurrent(defaultGroup, defaultTopic);
+ assertEquals(AdminToolsResultCodeEnum.CONSUMER_NOT_ONLINE.getCode(), actual.getCode());
+ }
+
+ @Test
+ public void testViewMessageValidMsgIdReturnsMessageExt() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ MessageExt expected = createMessageExt();
+ when(mqAdminImpl.viewMessage(anyString(), anyString())).thenReturn(expected);
+ when(mqClientInstance.getMQAdminImpl()).thenReturn(mqAdminImpl);
+ MessageExt actual = defaultMQAdminExtImpl.viewMessage(expected.getTopic(), expected.getMsgId());
+ assertNotNull(actual);
+ assertEquals(expected.getMsgId(), actual.getMsgId());
+ assertEquals(expected.getTopic(), actual.getTopic());
+ }
+
+ @Test
+ public void testViewMessageInvalidMsgIdQueriesByUniqKey() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ MessageExt expected = createMessageExt();
+ expected.setMsgId("invalidMsgId");
+ when(mqAdminImpl.queryMessageByUniqKey(anyString(), anyString())).thenReturn(expected);
+ when(mqClientInstance.getMQAdminImpl()).thenReturn(mqAdminImpl);
+ MessageExt actual = defaultMQAdminExtImpl.viewMessage(expected.getTopic(), expected.getMsgId());
+ assertNotNull(actual);
+ assertEquals(expected.getMsgId(), actual.getMsgId());
+ assertEquals(expected.getTopic(), actual.getTopic());
+ }
+
+ @Test
+ public void testViewMessageExceptionInDecodeLogsWarningAndQueriesByUniqKey() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ MessageExt expected = createMessageExt();
+ expected.setMsgId("exceptionMsgId");
+ when(mqAdminImpl.queryMessageByUniqKey(anyString(), anyString())).thenReturn(expected);
+ MessageExt actual = defaultMQAdminExtImpl.viewMessage(expected.getTopic(), expected.getMsgId());
+ assertNotNull(actual);
+ assertEquals(expected.getMsgId(), actual.getMsgId());
+ assertEquals(expected.getTopic(), actual.getTopic());
+ }
+
+ @Test
+ public void testQueryMessageInvalidMsgIdReturnsMessageExt() throws Exception {
+ MessageExt expected = createMessageExt();
+ expected.setMsgId("invalidMsgId");
+ when(mqAdminImpl.queryMessageByUniqKey(anyString(), anyString(), anyString())).thenReturn(expected);
+ MessageExt actual = defaultMQAdminExtImpl.queryMessage(defaultCluster, expected.getTopic(), expected.getMsgId());
+ assertNotNull(actual);
+ assertEquals(expected.getMsgId(), actual.getMsgId());
+ assertEquals(expected.getTopic(), actual.getTopic());
+ }
+
+ @Test
+ public void testQueryMessageRemotingException() throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
+ when(mqAdminImpl.viewMessage(anyString(), anyString())).thenThrow(new RemotingException("Test Exception"));
+ assertNull(defaultMQAdminExtImpl.queryMessage(null, defaultTopic, defaultMsgId));
+ }
+
+ @Test
+ public void testDeleteTopicValidInput() throws Exception {
+ ClusterInfo clusterInfo = mock(ClusterInfo.class);
+ when(defaultMQAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
+ Map<String, Set<String>> clusterAddrTable = new HashMap<>();
+ clusterAddrTable.put(defaultCluster, new HashSet<>(Arrays.asList("broker1", "broker2")));
+ when(clusterInfo.getClusterAddrTable()).thenReturn(clusterAddrTable);
+ Map<String, BrokerData> brokerAddrTable = new HashMap<>();
+ BrokerData brokerData = new BrokerData();
+ brokerData.setBrokerName(defaultBroker);
+ HashMap<Long, String> brokerAddrs = new HashMap<>();
+ brokerAddrs.put(0L, defaultBrokerAddr);
+ brokerData.setBrokerAddrs(brokerAddrs);
+ brokerAddrTable.put(defaultBroker, brokerData);
+ when(clusterInfo.getBrokerAddrTable()).thenReturn(brokerAddrTable);
+ List<String> nsAddrs = new ArrayList<>();
+ nsAddrs.add("127.0.0.1:9876");
+ when(mqClientAPIImpl.getNameServerAddressList()).thenReturn(nsAddrs);
+ List<String> kvNamespaceToDeleteList = new ArrayList<>();
+ kvNamespaceToDeleteList.add("namespace");
+ FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "kvNamespaceToDeleteList", kvNamespaceToDeleteList, true);
+ defaultMQAdminExtImpl.deleteTopic(defaultTopic, defaultCluster);
+ verify(mqClientAPIImpl, times(1)).deleteTopicInBroker(any(), any(), anyLong());
+ verify(mqClientAPIImpl, times(1)).deleteTopicInNameServer(any(), any(), anyLong());
+ verify(mqClientAPIImpl, times(1)).deleteKVConfigValue(any(), any(), anyLong());
+ }
+
+ @Test
+ public void testDeleteTopicInBrokerConcurrent() throws InterruptedException, RemotingException, MQClientException {
+ Set<String> addrs = Collections.singleton(defaultBrokerAddr);
+ doNothing().when(mqClientAPIImpl).deleteTopicInBroker(anyString(), anyString(), anyLong());
+ AdminToolResult<BrokerOperatorResult> result = defaultMQAdminExtImpl.deleteTopicInBrokerConcurrent(addrs, defaultTopic);
+ assertNotNull(result);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), result.getCode());
+ BrokerOperatorResult brokerResult = result.getData();
+ List<String> successList = brokerResult.getSuccessList();
+ List<String> failureList = brokerResult.getFailureList();
+ assertEquals(1, successList.size());
+ assertEquals(0, failureList.size());
+ assertEquals(addrs.iterator().next(), successList.get(0));
+ }
+
+ @Test
+ public void testDeleteTopicInBrokerConcurrentAllFailures() throws InterruptedException, RemotingException, MQClientException {
+ Set<String> addrs = new HashSet<>(Collections.singleton(defaultBrokerAddr));
+ String anotherAddr = "anotherBrokerAddr:10911";
+ addrs.add(anotherAddr);
+ doThrow(new RuntimeException("deleteTopic error")).when(mqClientAPIImpl).deleteTopicInBroker(anyString(), anyString(), anyLong());
+ AdminToolResult<BrokerOperatorResult> result = defaultMQAdminExtImpl.deleteTopicInBrokerConcurrent(addrs, defaultTopic);
+ assertNotNull(result);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), result.getCode());
+ BrokerOperatorResult brokerResult = result.getData();
+ List<String> successList = brokerResult.getSuccessList();
+ List<String> failureList = brokerResult.getFailureList();
+ assertEquals(0, successList.size());
+ assertEquals(2, failureList.size());
+ assertTrue(failureList.contains(defaultBrokerAddr));
+ assertTrue(failureList.contains(anotherAddr));
+ }
+
+ @Test
+ public void testResetOffsetByTimestampOldThrowException() {
+ String topic = "nonExistentTopic";
+ long timestamp = System.currentTimeMillis();
+ assertThrows(NullPointerException.class, () -> defaultMQAdminExtImpl.resetOffsetByTimestampOld(defaultGroup, topic, timestamp, false));
+ }
+
+ @Test
+ public void testResetOffsetByTimestampOldValidInputShouldProcessCorrectly() throws Exception {
+ long timestamp = System.currentTimeMillis();
+ ConsumeStats consumeStats = mock(ConsumeStats.class);
+ Map<MessageQueue, OffsetWrapper> offsetTable = new ConcurrentHashMap<>();
+ OffsetWrapper offsetWrapper = new OffsetWrapper();
+ offsetWrapper.setBrokerOffset(5L);
+ offsetWrapper.setConsumerOffset(5L);
+ offsetTable.put(new MessageQueue(defaultTopic, defaultBroker, 0), offsetWrapper);
+ when(consumeStats.getOffsetTable()).thenReturn(offsetTable);
+ when(mqClientAPIImpl.getConsumeStats(any(), any(), anyLong())).thenReturn(consumeStats);
+ List<RollbackStats> rollbackStatsList = defaultMQAdminExtImpl.resetOffsetByTimestampOld(defaultGroup, defaultTopic, timestamp, false);
+ assertNotNull(rollbackStatsList);
+ assertEquals(1, rollbackStatsList.size());
+ RollbackStats rollbackStats = rollbackStatsList.get(0);
+ assertEquals(defaultBroker, rollbackStats.getBrokerName());
+ assertEquals(0, rollbackStats.getQueueId());
+ assertEquals(5L, rollbackStats.getBrokerOffset());
+ assertEquals(5L, rollbackStats.getConsumerOffset());
+ }
+
+ @Test
+ public void testResetOffsetNew() throws Exception {
+ defaultMQAdminExtImpl.resetOffsetNew(defaultGroup, defaultTopic, timeoutMillis);
+ verify(mqClientAPIImpl, times(1)).invokeBrokerToResetOffset(
+ anyString(),
+ anyString(),
+ anyString(),
+ anyLong(),
+ anyBoolean(),
+ anyLong(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testResetOffsetNewConcurrent() {
+ AdminToolResult<BrokerOperatorResult> actual = defaultMQAdminExtImpl.resetOffsetNewConcurrent(defaultGroup, defaultTopic, timeoutMillis);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+ }
+
+ @Test
+ public void testResetOffsetNewConcurrentTopicRouteInfoNotExist() throws Exception {
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+ AdminToolResult<BrokerOperatorResult> actual = defaultMQAdminExtImpl.resetOffsetNewConcurrent(defaultGroup, defaultTopic, timeoutMillis);
+ assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), actual.getCode());
+ }
+
+ @Test
+ public void testResetOffsetNewConcurrentException() throws Exception {
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenThrow(new MQClientException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+ AdminToolResult<BrokerOperatorResult> actual = defaultMQAdminExtImpl.resetOffsetNewConcurrent(defaultGroup, defaultTopic, timeoutMillis);
+ assertEquals(AdminToolsResultCodeEnum.MQ_CLIENT_ERROR.getCode(), actual.getCode());
+ }
+
+ @Test
+ public void testCreateOrUpdateOrderConfClusterConfig() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ String key = "key1";
+ String value = "value1";
+ doNothing().when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+ defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, true);
+ verify(mqClientAPIImpl, times(1)).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testCreateOrUpdateOrderConfNonClusterConfig() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ String key = "key1";
+ String value = "value1:value2";
+ String oldOrderConfs = "key1:value1;key2:value2";
+ when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenReturn(oldOrderConfs);
+ doNothing().when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+ defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false);
+ verify(mqClientAPIImpl, times(1)).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testCreateOrUpdateOrderConfExceptionInPut() throws RemotingException, InterruptedException, MQClientException {
+ String key = "key1";
+ String value = "value1:value2";
+ String oldOrderConfs = "key1:value1;key2:value2";
+ when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenReturn(oldOrderConfs);
+ doThrow(new RemotingException("Test Exception")).when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+ assertThrows(RemotingException.class, () -> defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false));
+ }
+
+ @Test
+ public void testCreateOrUpdateOrderConfNoOldConfs() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ String key = "key1";
+ String value = "value1:value2";
+ when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenReturn(null);
+ doNothing().when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+ defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false);
+ verify(mqClientAPIImpl, times(1)).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testCreateOrUpdateOrderConfExceptionInGet() throws RemotingException, InterruptedException, MQClientException, MQBrokerException {
+ String key = "key1";
+ String value = "value1:value2";
+ when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenThrow(new RemotingException("Test Exception"));
+ defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false);
+ verify(mqClientAPIImpl, times(1)).getKVConfigValue(anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testQuerySubscriptionValidInput() throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
+ when(mqClientAPIImpl.querySubscriptionByConsumer(anyString(), anyString(), anyString(), anyLong())).thenReturn(new SubscriptionData());
+ assertNotNull(defaultMQAdminExtImpl.querySubscription("group", "topic"));
+ }
+
+ @Test
+ public void testQueryTopicsByConsumer() throws Exception {
+ TopicList expected = new TopicList();
+ expected.getTopicList().add(defaultTopic);
+ when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenReturn(expected);
+ TopicList actual = defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup);
+ assertEquals(1, actual.getTopicList().size());
+ assertEquals(expected.getTopicList().iterator().next(), actual.getTopicList().iterator().next());
+ verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testQueryTopicsByConsumerRemotingTimeoutException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+ when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenThrow(new RemotingTimeoutException("Test Exception"));
+ assertThrows(RemotingTimeoutException.class, () -> defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup));
+ verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testQueryTopicsByConsumerMQBrokerException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+ when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+ assertThrows(MQBrokerException.class, () -> defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup));
+ verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testQueryTopicsByConsumerMQClientException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+ when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+ assertThrows(MQBrokerException.class, () -> defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup));
+ verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+ }
+
+ @Test
+ public void testQueryTopicsByConsumerNoBrokers() throws Exception {
+ TopicRouteData topicRouteData = new TopicRouteData();
+ topicRouteData.setBrokerDatas(new ArrayList<>());
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(topicRouteData);
+ TopicList actual = defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup);
+ assertEquals(0, actual.getTopicList().size());
+ }
+
+ @Test
+ public void testQueryTopicsByConsumerConcurrentTopicRouteDataNull() throws Exception {
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+ AdminToolResult<TopicList> actual = defaultMQAdminExtImpl.queryTopicsByConsumerConcurrent(defaultGroup);
+ assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), actual.getCode());
+ assertEquals("router info not found.", actual.getErrorMsg());
+ }
+
+ @Test
+ public void testQueryTopicsByConsumerConcurrentNoBrokers() throws Exception {
+ TopicRouteData topicRouteData = new TopicRouteData();
+ topicRouteData.setBrokerDatas(new ArrayList<>());
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(topicRouteData);
+ AdminToolResult<TopicList> actual = defaultMQAdminExtImpl.queryTopicsByConsumerConcurrent(defaultGroup);
+ assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), actual.getCode());
+ assertEquals("router info not found.", actual.getErrorMsg());
+ }
+
+ @Test
+ public void testQueryTopicsByConsumerConcurrent() throws Exception {
+ TopicList expectedTopicList = new TopicList();
+ expectedTopicList.setTopicList(new HashSet<>(Arrays.asList(defaultTopic, "topic2")));
+ when(mqClientAPIImpl.queryTopicsByConsumer(any(), any(), anyLong())).thenReturn(expectedTopicList);
+ AdminToolResult<TopicList> result = defaultMQAdminExtImpl.queryTopicsByConsumerConcurrent(defaultGroup);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), result.getCode());
+ Set<String> actual = result.getData().getTopicList();
+ assertFalse(actual.isEmpty());
+ assertTrue(actual.containsAll(expectedTopicList.getTopicList()));
+ }
+
+ @Test
+ public void testQueryConsumeTimeSpanConcurrentTopicRouteDataNull() throws Exception {
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(anyString(), anyLong())).thenReturn(null);
+ AdminToolResult<List<QueueTimeSpan>> actual = defaultMQAdminExtImpl.queryConsumeTimeSpanConcurrent(defaultTopic, defaultGroup);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+ assertEquals(0, actual.getData().size());
+ }
+
+ @Test
+ public void testQueryConsumeTimeSpanConcurrentNoBrokers() throws Exception {
+ TopicRouteData topicRouteData = new TopicRouteData();
+ topicRouteData.setBrokerDatas(new ArrayList<>());
+ when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(anyString(), anyLong())).thenReturn(topicRouteData);
+ AdminToolResult<List<QueueTimeSpan>> actual = defaultMQAdminExtImpl.queryConsumeTimeSpanConcurrent(defaultTopic, defaultGroup);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+ assertEquals(0, actual.getData().size());
+ }
+
+ @Test
+ public void testQueryConsumeTimeSpanConcurrent() throws Exception {
+ List<QueueTimeSpan> spans = new ArrayList<>();
+ QueueTimeSpan queueTimeSpan = new QueueTimeSpan();
+ queueTimeSpan.setMinTimeStamp(1000L);
+ queueTimeSpan.setMaxTimeStamp(2000L);
+ spans.add(queueTimeSpan);
+ when(mqClientAPIImpl.queryConsumeTimeSpan(anyString(), anyString(), anyString(), anyLong())).thenReturn(spans);
+ AdminToolResult<List<QueueTimeSpan>> actual = defaultMQAdminExtImpl.queryConsumeTimeSpanConcurrent(defaultTopic, defaultGroup);
+ assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+ assertEquals(1, actual.getData().size());
+ }
+
+ @Test
+ public void testDeleteExpiredCommitLog() throws Exception {
+ ClusterInfo clusterInfo = mock(ClusterInfo.class);
+ when(clusterInfo.retrieveAllAddrByCluster(defaultCluster)).thenReturn(new String[]{"addr1", "addr2"});
+ when(mqClientAPIImpl.getBrokerClusterInfo(anyLong())).thenReturn(clusterInfo);
+ when(mqClientAPIImpl.deleteExpiredCommitLog(anyString(), anyLong())).thenReturn(true);
+ boolean actual = defaultMQAdminExtImpl.deleteExpiredCommitLog(defaultCluster);
+ assertTrue(actual);
+ verify(mqClientAPIImpl, times(2)).deleteExpiredCommitLog(anyString(), anyLong());
+ }
+
+ @Test
+ public void testDeleteExpiredCommitLogByCluster() throws Exception {
+ ClusterInfo clusterInfo = mock(ClusterInfo.class);
+ when(clusterInfo.retrieveAllAddrByCluster(defaultCluster)).thenReturn(new String[]{"addr1", "addr2"});
+ when(mqClientAPIImpl.deleteExpiredCommitLog(anyString(), anyLong())).thenReturn(true);
+ boolean actual = defaultMQAdminExtImpl.deleteExpiredCommitLogByCluster(clusterInfo, defaultCluster);
+ assertTrue(actual);
+ verify(mqClientAPIImpl, times(2)).deleteExpiredCommitLog(anyString(), anyLong());
+ }
+
+ @Test
+ public void testDeleteExpiredCommitLogByAddr() throws Exception {
+ when(mqClientAPIImpl.deleteExpiredCommitLog(defaultBrokerAddr, timeoutMillis)).thenReturn(true);
+ boolean actual = defaultMQAdminExtImpl.deleteExpiredCommitLogByAddr(defaultBrokerAddr);
+ assertTrue(actual);
+ verify(mqClientAPIImpl, times(1)).deleteExpiredCommitLog(defaultBrokerAddr, timeoutMillis);
+ }
+
+ @Test
+ public void testConsumeMessageDirectly() throws Exception {
+ String clientId = "clientId";
+ MessageExt messageExt = createMessageExt();
+ when(mqAdminImpl.viewMessage(defaultTopic, defaultMsgId)).thenReturn(messageExt);
+ ConsumeMessageDirectlyResult consumeMessageDirectlyResult = mock(ConsumeMessageDirectlyResult.class);
+ when(mqClientAPIImpl.consumeMessageDirectly(
+ anyString(),
+ anyString(),
+ anyString(),
+ anyString(),
+ anyString(),
+ anyLong()))
+ .thenReturn(consumeMessageDirectlyResult);
+ ConsumeMessageDirectlyResult actual = defaultMQAdminExtImpl.consumeMessageDirectly(defaultGroup, clientId, defaultTopic, defaultMsgId);
+ assertNotNull(actual);
+ assertNull(actual.getRemark());
+ assertFalse(actual.isAutoCommit());
+ assertFalse(actual.isOrder());
+ }
+
+ @Test
+ public void testMessageTrackDetailConcurrent() throws Exception {
+ MessageExt messageExt = createMessageExt();
+ GroupList groupList = mock(GroupList.class);
+ HashSet<String> groupSet = new HashSet<>();
+ groupSet.add(defaultGroup);
+ when(groupList.getGroupList()).thenReturn(groupSet);
+ when(mqClientAPIImpl.queryTopicConsumeByWho(anyString(), anyString(), anyLong())).thenReturn(groupList);
+ ConsumerConnection consumerConnection = mock(ConsumerConnection.class);
+ when(mqClientAPIImpl.getConsumerConnectionList(anyString(), anyString(), anyLong())).thenReturn(consumerConnection);
+ List<MessageTrack> actual = defaultMQAdminExtImpl.messageTrackDetailConcurrent(messageExt);
+ assertEquals(1, actual.size());
+ }
+
+// @Test
+// public void testConsumedConcurrent() throws Exception {
+// ConsumeStats consumeStats = mock(ConsumeStats.class);
+// ClusterInfo ci = mock(ClusterInfo.class);
+// Map<String, BrokerData> brokerAddrTable = new HashMap<>();
+// BrokerData brokerData = mock(BrokerData.class);
+// HashMap<Long, String> brokerAddress = new HashMap<>();
+// brokerAddress.put(0L, defaultBrokerAddr);
+// when(brokerData.getBrokerAddrs()).thenReturn(brokerAddress);
+// brokerAddrTable.put(defaultBroker, brokerData);
+// when(ci.getBrokerAddrTable()).thenReturn(brokerAddrTable);
+// Map<MessageQueue, OffsetWrapper> offsetTable = new HashMap<>();
+// OffsetWrapper offsetWrapper = new OffsetWrapper();
+// offsetWrapper.setConsumerOffset(1L);
+// offsetTable.put(new MessageQueue(defaultTopic, defaultBroker, 0), offsetWrapper);
+// when(consumeStats.getOffsetTable()).thenReturn(offsetTable);
+//// when(mqClientAPIImpl.getConsumeStats(any(), any(), any(), anyLong())).thenReturn(consumeStats);
+// when(mqClientAPIImpl.getBrokerClusterInfo(anyLong())).thenReturn(ci);
+//// assertTrue(defaultMQAdminExtImpl.consumedConcurrent(createMessageExt(), defaultGroup));
+// }
+
+ @Test
+ public void testCloneGroupOffsetValidInput() throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
+ String srcGroup = "srcGroup";
+ String destGroup = "destGroup";
+ boolean isOffline = false;
+ defaultMQAdminExtImpl.cloneGroupOffset(srcGroup, destGroup, defaultTopic, isOffline);
+ verify(mqClientAPIImpl, times(1)).cloneGroupOffset(
+ anyString(),
+ anyString(),
+ anyString(),
+ anyString(),
+ anyBoolean(),
+ anyLong());
+ }
+
+ @Test
+ public void testGetUserSubscriptionGroup() throws Exception {
+ SubscriptionGroupWrapper subscriptionGroupWrapper = new SubscriptionGroupWrapper();
+ ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable = new ConcurrentHashMap<>();
+ SubscriptionGroupConfig groupConfig1 = new SubscriptionGroupConfig();
+ groupConfig1.setGroupName("CID_RMQ_SYS_GROUP");
+ SubscriptionGroupConfig groupConfig2 = new SubscriptionGroupConfig();
+ groupConfig2.setGroupName("DEFAULT_CONSUMER");
+ SubscriptionGroupConfig groupConfig3 = new SubscriptionGroupConfig();
+ groupConfig3.setGroupName("SYS_CONSUMER_GROUP");
+ subscriptionGroupTable.put(groupConfig1.getGroupName(), groupConfig1);
+ subscriptionGroupTable.put(groupConfig2.getGroupName(), groupConfig2);
+ subscriptionGroupTable.put(groupConfig3.getGroupName(), groupConfig3);
+ subscriptionGroupWrapper.setSubscriptionGroupTable(subscriptionGroupTable);
+ when(mqClientAPIImpl.getAllSubscriptionGroup(any(), anyLong())).thenReturn(subscriptionGroupWrapper);
+ SubscriptionGroupWrapper actual = defaultMQAdminExtImpl.getUserSubscriptionGroup(defaultBrokerAddr, timeoutMillis);
+ assertEquals(1, actual.getSubscriptionGroupTable().size());
+ assertTrue(actual.getSubscriptionGroupTable().containsKey("SYS_CONSUMER_GROUP"));
+ }
+
+ @Test
+ public void testGetUserTopicConfig() throws Exception {
+ TopicConfigSerializeWrapper topicConfigSerializeWrapper = new TopicConfigSerializeWrapper();
+ ConcurrentMap<String, TopicConfig> topicConfigMap = new ConcurrentHashMap<>();
+ topicConfigMap.put("Topic1", new TopicConfig("Topic1", 1, 1, 0));
+ topicConfigMap.put("Topic2", new TopicConfig("Topic2", 1, 1, 1));
+ topicConfigSerializeWrapper.setTopicConfigTable(topicConfigMap);
+ TopicList topicList = new TopicList();
+ Set<String> topicSet = new HashSet<>();
+ topicSet.add("Topic2");
+ topicList.setTopicList(topicSet);
+ when(mqClientAPIImpl.getAllTopicConfig(any(), anyLong())).thenReturn(topicConfigSerializeWrapper);
+ when(mqClientAPIImpl.getSystemTopicListFromBroker(anyString(), anyLong())).thenReturn(topicList);
+ TopicConfigSerializeWrapper actual = defaultMQAdminExtImpl.getUserTopicConfig("brokerAddr", false, timeoutMillis);
+ assertEquals(1, actual.getTopicConfigTable().size());
+ }
+
+ @Test
+ public void testUpdateConsumeOffset() throws Exception {
+ doNothing().when(mqClientAPIImpl).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+ defaultMQAdminExtImpl.updateConsumeOffset(defaultBrokerAddr, defaultGroup, createMessageQueue(), 1L);
+ verify(mqClientAPIImpl, times(1)).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+ }
+
+ @Test
+ public void testUpdateConsumeOffsetException() throws MQBrokerException, RemotingException, InterruptedException {
+ doThrow(new RemotingException("Test exception")).when(mqClientAPIImpl).updateConsumerOffset(anyString(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+ assertThrows(RemotingException.class,
+ () -> defaultMQAdminExtImpl.updateConsumeOffset(defaultBrokerAddr, defaultGroup, createMessageQueue(), 1L));
+ }
+
+ @Test
+ public void testResetOffsetByQueueId() throws Exception {
+ long resetOffset = 100;
+ doNothing().when(mqClientAPIImpl).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+ Map<MessageQueue, Long> result = new HashMap<>();
+ result.put(createMessageQueue(), resetOffset);
+ when(mqClientAPIImpl.invokeBrokerToResetOffset(anyString(), anyString(), anyString(), anyLong(), anyInt(), anyLong(), anyLong())).thenReturn(result);
+ defaultMQAdminExtImpl.resetOffsetByQueueId(defaultBrokerAddr, defaultGroup, defaultTopic, 0, resetOffset);
+ verify(mqClientAPIImpl, times(1)).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+ verify(mqClientAPIImpl, times(1)).invokeBrokerToResetOffset(
+ anyString(),
+ anyString(),
+ anyString(),
+ anyLong(),
+ anyInt(),
+ anyLong(),
+ anyLong());
+ }
+
+ @Test
+ public void testResetOffsetByQueueIdThrowsException() throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
+ doNothing().when(mqClientAPIImpl).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+ when(mqClientAPIImpl.invokeBrokerToResetOffset(
+ anyString(),
+ anyString(),
+ anyString(),
+ anyLong(),
+ anyInt(),
+ anyLong(),
+ anyLong()))
+ .thenThrow(new MQClientException(1, "Exception"));
+ assertThrows(MQBrokerException.class,
+ () -> defaultMQAdminExtImpl.resetOffsetByQueueId(defaultBrokerAddr, defaultGroup, defaultTopic, 0, 100));
+ }
+
+ @Test
+ public void testUpdateAndGetGroupReadForbidden() throws RemotingException, InterruptedException, MQBrokerException {
+ boolean readable = true;
+ GroupForbidden expectedResponse = new GroupForbidden();
+ expectedResponse.setGroup(defaultGroup);
+ expectedResponse.setTopic(defaultTopic);
+ expectedResponse.setReadable(readable);
+ when(mqClientAPIImpl.updateAndGetGroupForbidden(any(), any(UpdateGroupForbiddenRequestHeader.class), anyLong())).thenReturn(expectedResponse);
+ GroupForbidden actual = defaultMQAdminExtImpl.updateAndGetGroupReadForbidden(defaultBrokerAddr, defaultGroup, defaultTopic, readable);
+ assertNotNull(actual);
+ assertEquals(defaultGroup, actual.getGroup());
+ assertEquals(defaultTopic, actual.getTopic());
+ assertEquals(readable, actual.getReadable());
+ }
+
+ @Test
+ public void testUpdateAndGetGroupReadForbiddenException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+ when(mqClientAPIImpl.updateAndGetGroupForbidden(any(), any(UpdateGroupForbiddenRequestHeader.class), anyLong()))
+ .thenThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+ assertThrows(MQBrokerException.class,
+ () -> defaultMQAdminExtImpl.updateAndGetGroupReadForbidden(defaultBrokerAddr, defaultGroup, defaultTopic, true));
+ }
+
+ private HashMap<Long, String> createBrokerAddrs() {
+ HashMap<Long, String> result = new HashMap<>();
+ result.put(0L, defaultBrokerAddr);
+ return result;
+ }
+
+ private TopicRouteData createTopicRouteData() {
+ BrokerData bd = new BrokerData(defaultCluster, defaultBroker, new HashMap<>());
+ bd.setBrokerAddrs(new HashMap<>());
+ bd.getBrokerAddrs().put(0L, defaultBrokerAddr);
+ QueueData qd = new QueueData();
+ qd.setBrokerName(defaultBroker);
+ qd.setPerm(PermName.PERM_WRITE);
+ qd.setReadQueueNums(1);
+ qd.setTopicSysFlag(0);
+ qd.setWriteQueueNums(1);
+ TopicRouteData result = new TopicRouteData();
+ result.getBrokerDatas().add(bd);
+ result.getQueueDatas().add(qd);
+ return result;
+ }
+
+ private MessageQueue createMessageQueue() {
+ return new MessageQueue(defaultTopic, defaultBroker, 0);
+ }
+
+ private MessageExt createMessageExt() {
+ MessageExt result = new MessageExt();
+ result.setMsgId(defaultMsgId);
+ result.setTopic(defaultTopic);
+ result.setQueueId(0);
+ InetAddress inetAddress = mock(InetAddress.class);
+ InetSocketAddress address = new InetSocketAddress(inetAddress, 10911);
+ when(inetAddress.getHostAddress()).thenReturn("127.0.0.1");
+ result.setStoreHost(address);
+ return result;
+ }
+}
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java
index f5967f5a30..a2ad8c5d85 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java
@@ -16,7 +16,6 @@
*/
package org.apache.rocketmq.tools.command.connection;
-import java.util.HashSet;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
@@ -30,7 +29,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static org.mockito.Mockito.mock;
+import java.util.HashSet;
public class ConsumerConnectionSubCommandTest {
private ServerResponseMocker brokerMocker;
@@ -62,7 +61,7 @@ public class ConsumerConnectionSubCommandTest {
private ServerResponseMocker startOneBroker() {
ConsumerConnection consumerConnection = new ConsumerConnection();
HashSet<Connection> connectionSet = new HashSet<>();
- Connection connection = mock(Connection.class);
+ Connection connection = new Connection();
connectionSet.add(connection);
consumerConnection.setConnectionSet(connectionSet);
// start broker
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java
index 672e4113d6..812edde9e0 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java
@@ -16,7 +16,6 @@
*/
package org.apache.rocketmq.tools.command.connection;
-import java.util.HashSet;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
@@ -30,7 +29,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static org.mockito.Mockito.mock;
+import java.util.HashSet;
public class ProducerConnectionSubCommandTest {
@@ -64,7 +63,7 @@ public class ProducerConnectionSubCommandTest {
private ServerResponseMocker startOneBroker() {
ProducerConnection producerConnection = new ProducerConnection();
HashSet<Connection> connectionSet = new HashSet<>();
- Connection connection = mock(Connection.class);
+ Connection connection = new Connection();
connectionSet.add(connection);
producerConnection.setConnectionSet(connectionSet);
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java
index 4651113c68..9f4da15fa3 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java
@@ -16,7 +16,6 @@
*/
package org.apache.rocketmq.tools.command.consumer;
-import java.util.HashSet;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
@@ -30,7 +29,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static org.mockito.Mockito.mock;
+import java.util.HashSet;
public class ConsumerStatusSubCommandTest {
@@ -65,7 +64,7 @@ public class ConsumerStatusSubCommandTest {
private ServerResponseMocker startOneBroker() {
ConsumerConnection consumerConnection = new ConsumerConnection();
HashSet<Connection> connectionSet = new HashSet<>();
- Connection connection = mock(Connection.class);
+ Connection connection = new Connection();
connectionSet.add(connection);
consumerConnection.setConnectionSet(connectionSet);
// start broker
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java
index e4e5e970c6..7ff4c42851 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java
@@ -16,9 +16,6 @@
*/
package org.apache.rocketmq.tools.command.consumer;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
@@ -33,7 +30,9 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import static org.mockito.Mockito.mock;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
public class GetConsumerConfigSubCommandTest {
@@ -91,7 +90,7 @@ public class GetConsumerConfigSubCommandTest {
private ServerResponseMocker startOneBroker() {
ConsumerConnection consumerConnection = new ConsumerConnection();
HashSet<Connection> connectionSet = new HashSet<>();
- Connection connection = mock(Connection.class);
+ Connection connection = new Connection();
connectionSet.add(connection);
consumerConnection.setConnectionSet(connectionSet);
// start broker
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java
index 7039c05fba..b1ebb924e7 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java
@@ -17,13 +17,12 @@
package org.apache.rocketmq.tools.command.producer;
-import java.util.HashMap;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
-import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
-import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
+import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.protocol.body.ProducerInfo;
+import org.apache.rocketmq.remoting.protocol.body.ProducerTableInfo;
import org.apache.rocketmq.srvutil.ServerUtil;
import org.apache.rocketmq.tools.command.SubCommandException;
import org.apache.rocketmq.tools.command.server.NameServerMocker;
@@ -32,6 +31,10 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
public class ProducerSubCommandTest {
private ServerResponseMocker brokerMocker;
@@ -61,21 +64,16 @@ public class ProducerSubCommandTest {
}
private ServerResponseMocker startOneBroker() {
- ConsumeStats consumeStats = new ConsumeStats();
- HashMap<MessageQueue, OffsetWrapper> offsetTable = new HashMap<>();
- MessageQueue messageQueue = new MessageQueue();
- messageQueue.setBrokerName("mockBrokerName");
- messageQueue.setQueueId(1);
- messageQueue.setBrokerName("mockTopicName");
-
- OffsetWrapper offsetWrapper = new OffsetWrapper();
- offsetWrapper.setBrokerOffset(1);
- offsetWrapper.setConsumerOffset(1);
- offsetWrapper.setLastTimestamp(System.currentTimeMillis());
+ ProducerTableInfo producerTableInfo = new ProducerTableInfo(new HashMap<>());
+ List<ProducerInfo> producerInfo = new ArrayList<>();
+ producerInfo.add(new ProducerInfo(
+ "xxxx-client-id",
+ "127.0.0.1:18978",
+ LanguageCode.JAVA,
+ 400,
+ System.currentTimeMillis()));
- offsetTable.put(messageQueue, offsetWrapper);
- consumeStats.setOffsetTable(offsetTable);
- // start broker
- return ServerResponseMocker.startServer(consumeStats.encode());
+ producerTableInfo.getData().put("mockTopicName", producerInfo);
+ return ServerResponseMocker.startServer(producerTableInfo.encode());
}
}