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

[rocketmq-clients] 01/02: Add more tests

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

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

commit 912b37526452a8f328a4dfc382f4073074ea53b7
Author: Aaron Ai <ya...@gmail.com>
AuthorDate: Mon Mar 6 18:30:09 2023 +0800

    Add more tests
---
 .../examples/ProducerTransactionMessageExample.cs  |   2 +-
 csharp/examples/SimpleConsumerExample.cs           |   2 +-
 csharp/rocketmq-client-csharp/Broker.cs            |   2 +-
 csharp/rocketmq-client-csharp/ClientManager.cs     |   4 +-
 csharp/rocketmq-client-csharp/ClientMeter.cs       |   6 +-
 .../ConfigFileCredentialsProvider.cs               |  18 ++--
 csharp/rocketmq-client-csharp/Consumer.cs          |   2 +-
 .../ExponentialBackoffRetryPolicy.cs               |   6 +-
 csharp/rocketmq-client-csharp/IClientManager.cs    |  44 ++++++++-
 csharp/rocketmq-client-csharp/IConsumer.cs         |  27 ------
 csharp/rocketmq-client-csharp/IRetryPolicy.cs      |   7 +-
 csharp/rocketmq-client-csharp/Message.cs           |   4 +
 csharp/rocketmq-client-csharp/MessageQueue.cs      |   2 +-
 csharp/rocketmq-client-csharp/Producer.cs          |   8 +-
 csharp/rocketmq-client-csharp/PublishingMessage.cs |   2 +-
 .../rocketmq-client-csharp/PublishingSettings.cs   |   2 +-
 csharp/rocketmq-client-csharp/Resource.cs          |   4 +-
 csharp/rocketmq-client-csharp/Settings.cs          |   4 +-
 csharp/rocketmq-client-csharp/Topic.cs             |   4 +-
 .../rocketmq-client-csharp/TopicRouteException.cs  |  29 ------
 csharp/rocketmq-client-csharp/Transaction.cs       |   4 +-
 .../TransactionResolution.cs                       |   6 +-
 .../rocketmq-client-csharp.csproj                  |   2 +-
 csharp/tests/ConfigFileCredentialsProviderTest.cs  |  11 ++-
 csharp/tests/DateTimeTest.cs                       |  14 +--
 csharp/tests/EndpointsTest.cs                      |  17 +++-
 csharp/tests/MessageTest.cs                        |  22 ++++-
 csharp/tests/MqLogManagerTest.cs                   |   1 +
 csharp/tests/PublishingMessageTest.cs              | 103 +++++++++++++++++++++
 csharp/tests/SendResultTest.cs                     |  33 -------
 csharp/tests/SignatureTest.cs                      |  44 ---------
 csharp/tests/TopicTest.cs                          |  51 ----------
 csharp/tests/UnitTest1.cs                          |  82 ----------------
 csharp/tests/tests.csproj                          |   4 +-
 34 files changed, 238 insertions(+), 335 deletions(-)

diff --git a/csharp/examples/ProducerTransactionMessageExample.cs b/csharp/examples/ProducerTransactionMessageExample.cs
index f9c34ffa..1b5b7aa4 100644
--- a/csharp/examples/ProducerTransactionMessageExample.cs
+++ b/csharp/examples/ProducerTransactionMessageExample.cs
@@ -31,7 +31,7 @@ namespace examples
             public TransactionResolution Check(MessageView messageView)
             {
                 Logger.Info("Receive transaction check, messageId={}", messageView.MessageId);
-                return TransactionResolution.COMMIT;
+                return TransactionResolution.Commit;
             }
         }
 
diff --git a/csharp/examples/SimpleConsumerExample.cs b/csharp/examples/SimpleConsumerExample.cs
index 25fba533..fd0d9d7a 100644
--- a/csharp/examples/SimpleConsumerExample.cs
+++ b/csharp/examples/SimpleConsumerExample.cs
@@ -56,7 +56,7 @@ namespace examples
             var messageViews = await simpleConsumer.Receive(16, TimeSpan.FromSeconds(15));
             foreach (var message in messageViews)
             {
-                Logger.Info($"Received a message, topic={message.Topic}, message-id={message.MessageId}");
+                Logger.Info($"Received a message, topic={message.Topic}, message-id={message.MessageId}, body-size={message.Body.Length}");
                 await simpleConsumer.Ack(message);
                 Logger.Info($"Message is acknowledged successfully, message-id={message.MessageId}");
                 // await simpleConsumer.ChangeInvisibleDuration(message, TimeSpan.FromSeconds(15));
diff --git a/csharp/rocketmq-client-csharp/Broker.cs b/csharp/rocketmq-client-csharp/Broker.cs
index 6a2f957a..d42d03b1 100644
--- a/csharp/rocketmq-client-csharp/Broker.cs
+++ b/csharp/rocketmq-client-csharp/Broker.cs
@@ -34,7 +34,7 @@ namespace Org.Apache.Rocketmq
 
         public Proto.Broker ToProtobuf()
         {
-            return new Proto.Broker()
+            return new Proto.Broker
             {
                 Name = Name,
                 Id = Id,
diff --git a/csharp/rocketmq-client-csharp/ClientManager.cs b/csharp/rocketmq-client-csharp/ClientManager.cs
index 9d0b92a5..808d73f1 100644
--- a/csharp/rocketmq-client-csharp/ClientManager.cs
+++ b/csharp/rocketmq-client-csharp/ClientManager.cs
@@ -27,13 +27,13 @@ namespace Org.Apache.Rocketmq
     public class ClientManager : IClientManager
     {
         private readonly Client _client;
-        private readonly Dictionary<Endpoints, RpcClient> _rpcClients;
+        private readonly Dictionary<Endpoints, IRpcClient> _rpcClients;
         private readonly ReaderWriterLockSlim _clientLock;
 
         public ClientManager(Client client)
         {
             _client = client;
-            _rpcClients = new Dictionary<Endpoints, RpcClient>();
+            _rpcClients = new Dictionary<Endpoints, IRpcClient>();
             _clientLock = new ReaderWriterLockSlim();
         }
 
diff --git a/csharp/rocketmq-client-csharp/ClientMeter.cs b/csharp/rocketmq-client-csharp/ClientMeter.cs
index 53fc2cdf..e4360cd1 100644
--- a/csharp/rocketmq-client-csharp/ClientMeter.cs
+++ b/csharp/rocketmq-client-csharp/ClientMeter.cs
@@ -38,11 +38,11 @@ namespace Org.Apache.Rocketmq
             ClientId = clientId;
         }
 
-        public Endpoints Endpoints { get; }
+        private Endpoints Endpoints { get; }
 
-        public MeterProvider MeterProvider { get; }
+        private MeterProvider MeterProvider { get; }
 
-        public string ClientId { get; }
+        private string ClientId { get; }
 
         public bool Enabled { get; }
 
diff --git a/csharp/rocketmq-client-csharp/ConfigFileCredentialsProvider.cs b/csharp/rocketmq-client-csharp/ConfigFileCredentialsProvider.cs
index b30d85d5..93b9e9ef 100644
--- a/csharp/rocketmq-client-csharp/ConfigFileCredentialsProvider.cs
+++ b/csharp/rocketmq-client-csharp/ConfigFileCredentialsProvider.cs
@@ -23,13 +23,12 @@ using NLog;
 
 namespace Org.Apache.Rocketmq
 {
-
     /**
      * File-based credentials provider that reads JSON configurations from ${HOME}/.rocketmq/config
      * A sample config content is as follows:
      * {"AccessKey": "key", "AccessSecret": "secret"}
      */
-    public class ConfigFileCredentialsProvider 
+    public class ConfigFileCredentialsProvider
     {
         private static readonly Logger Logger = MqLogManager.Instance.GetCurrentClassLogger();
 
@@ -53,7 +52,7 @@ namespace Org.Apache.Rocketmq
                     Logger.Error($"Failed to parse JSON configuration: {json}");
                     return;
                 }
-                
+
                 _accessKey = kv["AccessKey"];
                 _accessSecret = kv["AccessSecret"];
                 _valid = true;
@@ -66,19 +65,14 @@ namespace Org.Apache.Rocketmq
 
         public SessionCredentials GetCredentials()
         {
-            if (!_valid)
-            {
-                return null;
-            }
-
-            return new SessionCredentials(_accessKey, _accessSecret);
+            return !_valid ? null : new SessionCredentials(_accessKey, _accessSecret);
         }
 
-        public static String DefaultConfigFilePath()
+        public static string DefaultConfigFilePath()
         {
             var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
-            string[] pathSegments = {home, ".rocketmq", "config"}; 
-            return String.Join(Path.DirectorySeparatorChar, pathSegments);
+            string[] pathSegments = { home, ".rocketmq", "config" };
+            return string.Join(Path.DirectorySeparatorChar, pathSegments);
         }
 
         private readonly string _accessKey;
diff --git a/csharp/rocketmq-client-csharp/Consumer.cs b/csharp/rocketmq-client-csharp/Consumer.cs
index 3444fbc0..998a3766 100644
--- a/csharp/rocketmq-client-csharp/Consumer.cs
+++ b/csharp/rocketmq-client-csharp/Consumer.cs
@@ -42,7 +42,7 @@ namespace Org.Apache.Rocketmq
             var tolerance = ClientConfig.RequestTimeout;
             var timeout = tolerance.Add(awaitDuration);
             var invocation = await ClientManager.ReceiveMessage(mq.Broker.Endpoints, request, timeout);
-            var status = new Proto.Status()
+            var status = new Proto.Status
             {
                 Code = Proto.Code.InternalServerError,
                 Message = "Status was not set by server"
diff --git a/csharp/rocketmq-client-csharp/ExponentialBackoffRetryPolicy.cs b/csharp/rocketmq-client-csharp/ExponentialBackoffRetryPolicy.cs
index ddc4d281..d4826d85 100644
--- a/csharp/rocketmq-client-csharp/ExponentialBackoffRetryPolicy.cs
+++ b/csharp/rocketmq-client-csharp/ExponentialBackoffRetryPolicy.cs
@@ -39,11 +39,11 @@ namespace Org.Apache.Rocketmq
             return _maxAttempts;
         }
 
-        public TimeSpan InitialBackoff { get; }
+        private TimeSpan InitialBackoff { get; }
 
-        public TimeSpan MaxBackoff { get; }
+        private TimeSpan MaxBackoff { get; }
 
-        public double BackoffMultiplier { get; }
+        private double BackoffMultiplier { get; }
 
         public IRetryPolicy InheritBackoff(Proto.RetryPolicy retryPolicy)
         {
diff --git a/csharp/rocketmq-client-csharp/IClientManager.cs b/csharp/rocketmq-client-csharp/IClientManager.cs
index 47af0280..d69b0506 100644
--- a/csharp/rocketmq-client-csharp/IClientManager.cs
+++ b/csharp/rocketmq-client-csharp/IClientManager.cs
@@ -65,27 +65,61 @@ namespace Org.Apache.Rocketmq
         /// <summary>
         /// Send message to remote endpoints.
         /// </summary>
-        /// <param name="endpoints"></param>
-        /// <param name="request"></param>
-        /// <param name="timeout"></param>
+        /// <param name="endpoints">The target endpoints.</param>
+        /// <param name="request">gRPC request for message publishing.</param>
+        /// <param name="timeout">Request max duration.</param>
         /// <returns></returns>
         Task<RpcInvocation<SendMessageRequest, SendMessageResponse>> SendMessage(Endpoints endpoints,
             SendMessageRequest request, TimeSpan timeout);
 
+        /// <summary>
+        /// Query assignment to receive message for push consumer.
+        /// </summary>
+        /// <param name="endpoints">The target endpoints.</param>
+        /// <param name="request">gRPC request for querying assignment.</param>
+        /// <param name="timeout">Request max duration.</param>
+        /// <returns></returns>
         Task<RpcInvocation<QueryAssignmentRequest, QueryAssignmentResponse>> QueryAssignment(Endpoints endpoints,
             QueryAssignmentRequest request, TimeSpan timeout);
 
+        /// <summary>
+        /// Receive message from remote endpoints.
+        /// </summary>
+        /// <param name="endpoints">The target endpoints.</param>
+        /// <param name="request">gRPC request for message receiving.</param>
+        /// <param name="timeout">Request max duration.</param>
+        /// <returns></returns>
         Task<RpcInvocation<ReceiveMessageRequest, List<ReceiveMessageResponse>>> ReceiveMessage(Endpoints endpoints,
             ReceiveMessageRequest request,
             TimeSpan timeout);
 
+        /// <summary>
+        /// Message acknowledgement towards remote endpoints.
+        /// </summary>
+        /// <param name="endpoints">The target endpoints.</param>
+        /// <param name="request">gRPC request for message acknowledgement.</param>
+        /// <param name="timeout">Request max duration.</param>
+        /// <returns></returns>
         Task<RpcInvocation<AckMessageRequest, AckMessageResponse>> AckMessage(Endpoints endpoints,
             AckMessageRequest request, TimeSpan timeout);
 
+        /// <summary>
+        /// Change message invisible duration.
+        /// </summary>
+        /// <param name="endpoints">The target endpoints.</param>
+        /// <param name="request">gRPC request of changing message invisible duration.</param>
+        /// <param name="timeout">Request max duration.</param>
+        /// <returns></returns>
         Task<RpcInvocation<ChangeInvisibleDurationRequest, ChangeInvisibleDurationResponse>> ChangeInvisibleDuration(
-            Endpoints endpoints,
-            ChangeInvisibleDurationRequest request, TimeSpan timeout);
+            Endpoints endpoints, ChangeInvisibleDurationRequest request, TimeSpan timeout);
 
+        /// <summary>
+        /// Transaction ending request.
+        /// </summary>
+        /// <param name="endpoints">The target endpoints.</param>
+        /// <param name="request">gRPC request of ending transaction.</param>
+        /// <param name="timeout">Request max duration.</param>
+        /// <returns></returns>
         Task<RpcInvocation<EndTransactionRequest, EndTransactionResponse>> EndTransaction(Endpoints endpoints,
             EndTransactionRequest request, TimeSpan timeout);
 
diff --git a/csharp/rocketmq-client-csharp/IConsumer.cs b/csharp/rocketmq-client-csharp/IConsumer.cs
deleted file mode 100644
index 2ad0daba..00000000
--- a/csharp/rocketmq-client-csharp/IConsumer.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.
- */
-
-using System.Threading.Tasks;
-namespace Org.Apache.Rocketmq
-{
-    public interface IConsumer
-    {
-        Task Start();
-
-        Task Shutdown();
-    }
-}
\ No newline at end of file
diff --git a/csharp/rocketmq-client-csharp/IRetryPolicy.cs b/csharp/rocketmq-client-csharp/IRetryPolicy.cs
index 86d280eb..fe7e7116 100644
--- a/csharp/rocketmq-client-csharp/IRetryPolicy.cs
+++ b/csharp/rocketmq-client-csharp/IRetryPolicy.cs
@@ -45,6 +45,11 @@ namespace Org.Apache.Rocketmq
         /// <returns></returns>
         RetryPolicy ToProtobuf();
 
-        IRetryPolicy InheritBackoff(Proto.RetryPolicy retryPolicy);
+        /// <summary>
+        /// Inherit backoff of retry policy.
+        /// </summary>
+        /// <param name="retryPolicy"></param>
+        /// <returns></returns>
+        IRetryPolicy InheritBackoff(RetryPolicy retryPolicy);
     }
 }
\ No newline at end of file
diff --git a/csharp/rocketmq-client-csharp/Message.cs b/csharp/rocketmq-client-csharp/Message.cs
index 32c4352c..42c271a5 100644
--- a/csharp/rocketmq-client-csharp/Message.cs
+++ b/csharp/rocketmq-client-csharp/Message.cs
@@ -129,6 +129,8 @@ namespace Org.Apache.Rocketmq
 
             public Builder SetDeliveryTimestamp(DateTime deliveryTimestamp)
             {
+                Preconditions.CheckArgument(null == _messageGroup,
+                    "deliveryTimestamp and messageGroup should not be set at same time");
                 _deliveryTimestamp = deliveryTimestamp;
                 return this;
             }
@@ -137,6 +139,8 @@ namespace Org.Apache.Rocketmq
             {
                 Preconditions.CheckArgument(!string.IsNullOrWhiteSpace(messageGroup),
                     "messageGroup should not be null or white space");
+                Preconditions.CheckArgument(null == _deliveryTimestamp,
+                    "messageGroup and deliveryTimestamp should not be set at same time");
                 _messageGroup = messageGroup;
                 return this;
             }
diff --git a/csharp/rocketmq-client-csharp/MessageQueue.cs b/csharp/rocketmq-client-csharp/MessageQueue.cs
index b4504f12..e5146d52 100644
--- a/csharp/rocketmq-client-csharp/MessageQueue.cs
+++ b/csharp/rocketmq-client-csharp/MessageQueue.cs
@@ -37,7 +37,7 @@ namespace Org.Apache.Rocketmq
 
         public Broker Broker { get; }
 
-        public Resource TopicResource { get; }
+        private Resource TopicResource { get; }
 
         public Permission Permission { get; }
 
diff --git a/csharp/rocketmq-client-csharp/Producer.cs b/csharp/rocketmq-client-csharp/Producer.cs
index 6510909b..95ddf98b 100644
--- a/csharp/rocketmq-client-csharp/Producer.cs
+++ b/csharp/rocketmq-client-csharp/Producer.cs
@@ -293,12 +293,12 @@ namespace Org.Apache.Rocketmq
             var transactionResolution = _checker.Check(message);
             switch (transactionResolution)
             {
-                case TransactionResolution.COMMIT:
-                case TransactionResolution.ROLLBACK:
+                case TransactionResolution.Commit:
+                case TransactionResolution.Rollback:
                     await EndTransaction(endpoints, message.Topic, message.MessageId, command.TransactionId,
                         transactionResolution);
                     break;
-                case TransactionResolution.UNKNOWN:
+                case TransactionResolution.Unknown:
                 default:
                     break;
             }
@@ -321,7 +321,7 @@ namespace Org.Apache.Rocketmq
                 TransactionId = transactionId,
                 MessageId = messageId,
                 Topic = topicResource,
-                Resolution = TransactionResolution.COMMIT == resolution
+                Resolution = TransactionResolution.Commit == resolution
                     ? Proto.TransactionResolution.Commit
                     : Proto.TransactionResolution.Rollback
             };
diff --git a/csharp/rocketmq-client-csharp/PublishingMessage.cs b/csharp/rocketmq-client-csharp/PublishingMessage.cs
index b5c92f51..b65f4660 100644
--- a/csharp/rocketmq-client-csharp/PublishingMessage.cs
+++ b/csharp/rocketmq-client-csharp/PublishingMessage.cs
@@ -29,7 +29,7 @@ namespace Org.Apache.Rocketmq
     /// </summary>
     public class PublishingMessage : Message
     {
-        public MessageType MessageType { set; get; }
+        public MessageType MessageType { get; }
 
         internal string MessageId { get; }
 
diff --git a/csharp/rocketmq-client-csharp/PublishingSettings.cs b/csharp/rocketmq-client-csharp/PublishingSettings.cs
index fd442bbe..22423b56 100644
--- a/csharp/rocketmq-client-csharp/PublishingSettings.cs
+++ b/csharp/rocketmq-client-csharp/PublishingSettings.cs
@@ -31,7 +31,7 @@ namespace Org.Apache.Rocketmq
         private volatile int _maxBodySizeBytes = 4 * 1024 * 1024;
         private volatile bool _validateMessageType = true;
 
-        public PublishingSettings(string clientId, Endpoints endpoints, ExponentialBackoffRetryPolicy retryPolicy,
+        public PublishingSettings(string clientId, Endpoints endpoints, IRetryPolicy retryPolicy,
             TimeSpan requestTimeout, ConcurrentDictionary<string, bool> topics) : base(clientId, ClientType.Producer,
             endpoints, retryPolicy, requestTimeout)
         {
diff --git a/csharp/rocketmq-client-csharp/Resource.cs b/csharp/rocketmq-client-csharp/Resource.cs
index 3395a16f..5d339475 100644
--- a/csharp/rocketmq-client-csharp/Resource.cs
+++ b/csharp/rocketmq-client-csharp/Resource.cs
@@ -34,7 +34,7 @@ namespace Org.Apache.Rocketmq
             Name = name;
         }
 
-        public string Namespace { get; }
+        private string Namespace { get; }
         public string Name { get; }
 
         public Proto.Resource ToProtobuf()
@@ -48,7 +48,7 @@ namespace Org.Apache.Rocketmq
 
         public override string ToString()
         {
-            return String.IsNullOrEmpty(Namespace) ? Name : $"{Namespace}.{Name}";
+            return string.IsNullOrEmpty(Namespace) ? Name : $"{Namespace}.{Name}";
         }
     }
 }
\ No newline at end of file
diff --git a/csharp/rocketmq-client-csharp/Settings.cs b/csharp/rocketmq-client-csharp/Settings.cs
index 491aa564..0ee95fb0 100644
--- a/csharp/rocketmq-client-csharp/Settings.cs
+++ b/csharp/rocketmq-client-csharp/Settings.cs
@@ -28,7 +28,7 @@ namespace Org.Apache.Rocketmq
         protected volatile IRetryPolicy RetryPolicy;
         protected readonly TimeSpan RequestTimeout;
 
-        public Settings(string clientId, ClientType clientType, Endpoints endpoints, IRetryPolicy retryPolicy,
+        protected Settings(string clientId, ClientType clientType, Endpoints endpoints, IRetryPolicy retryPolicy,
             TimeSpan requestTimeout)
         {
             ClientId = clientId;
@@ -38,7 +38,7 @@ namespace Org.Apache.Rocketmq
             RequestTimeout = requestTimeout;
         }
 
-        public Settings(string clientId, ClientType clientType, Endpoints endpoints, TimeSpan requestTimeout)
+        protected Settings(string clientId, ClientType clientType, Endpoints endpoints, TimeSpan requestTimeout)
         {
             ClientId = clientId;
             ClientType = clientType;
diff --git a/csharp/rocketmq-client-csharp/Topic.cs b/csharp/rocketmq-client-csharp/Topic.cs
index f1ae453c..ff66b719 100644
--- a/csharp/rocketmq-client-csharp/Topic.cs
+++ b/csharp/rocketmq-client-csharp/Topic.cs
@@ -27,8 +27,8 @@ namespace Org.Apache.Rocketmq
             Name = name;
         }
 
-        public string ResourceNamespace { get; }
-        public string Name { get; }
+        private string ResourceNamespace { get; }
+        private string Name { get; }
 
         public bool Equals(Topic other)
         {
diff --git a/csharp/rocketmq-client-csharp/TopicRouteException.cs b/csharp/rocketmq-client-csharp/TopicRouteException.cs
deleted file mode 100644
index c80e8699..00000000
--- a/csharp/rocketmq-client-csharp/TopicRouteException.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.
- */
-
-using System;
-namespace Org.Apache.Rocketmq
-{
-    public class TopicRouteException : Exception
-    {
-        public TopicRouteException(string message) : base(message)
-        {
-
-        }
-
-    }
-}
\ No newline at end of file
diff --git a/csharp/rocketmq-client-csharp/Transaction.cs b/csharp/rocketmq-client-csharp/Transaction.cs
index 5084ae4e..5a0e81a6 100644
--- a/csharp/rocketmq-client-csharp/Transaction.cs
+++ b/csharp/rocketmq-client-csharp/Transaction.cs
@@ -105,7 +105,7 @@ namespace Org.Apache.Rocketmq
             foreach (var (publishingMessage, sendReceipt) in _messageSendReceiptDict)
             {
                 await _producer.EndTransaction(sendReceipt.Endpoints, publishingMessage.Topic, sendReceipt.MessageId,
-                    sendReceipt.TransactionId, TransactionResolution.COMMIT);
+                    sendReceipt.TransactionId, TransactionResolution.Commit);
             }
         }
 
@@ -124,7 +124,7 @@ namespace Org.Apache.Rocketmq
             foreach (var (publishingMessage, sendReceipt) in _messageSendReceiptDict)
             {
                 await _producer.EndTransaction(sendReceipt.Endpoints, publishingMessage.Topic, sendReceipt.MessageId,
-                    sendReceipt.TransactionId, TransactionResolution.ROLLBACK);
+                    sendReceipt.TransactionId, TransactionResolution.Rollback);
             }
         }
     }
diff --git a/csharp/rocketmq-client-csharp/TransactionResolution.cs b/csharp/rocketmq-client-csharp/TransactionResolution.cs
index 5bb4d5e1..89595570 100644
--- a/csharp/rocketmq-client-csharp/TransactionResolution.cs
+++ b/csharp/rocketmq-client-csharp/TransactionResolution.cs
@@ -19,8 +19,8 @@ namespace Org.Apache.Rocketmq
 {
     public enum TransactionResolution
     {
-        COMMIT,
-        ROLLBACK,
-        UNKNOWN
+        Commit,
+        Rollback,
+        Unknown
     }
 }
\ No newline at end of file
diff --git a/csharp/rocketmq-client-csharp/rocketmq-client-csharp.csproj b/csharp/rocketmq-client-csharp/rocketmq-client-csharp.csproj
index 94c2d718..ebbb8487 100644
--- a/csharp/rocketmq-client-csharp/rocketmq-client-csharp.csproj
+++ b/csharp/rocketmq-client-csharp/rocketmq-client-csharp.csproj
@@ -14,7 +14,7 @@
     <Description>.NET Client for Apache RocketMQ</Description>
     <PackageProjectUrl>https://github.com/apache/rocketmq-clients</PackageProjectUrl>
     <RepositoryUrl>https://github.com/apache/rocketmq-clients</RepositoryUrl>
-    <PackageVersion>0.0.6-SNAPSHOT</PackageVersion>
+    <PackageVersion>0.0.8-SNAPSHOT</PackageVersion>
     <PackageIcon>logo.png</PackageIcon>
   </PropertyGroup>
 
diff --git a/csharp/tests/ConfigFileCredentialsProviderTest.cs b/csharp/tests/ConfigFileCredentialsProviderTest.cs
index 0ebea9e3..7874795e 100644
--- a/csharp/tests/ConfigFileCredentialsProviderTest.cs
+++ b/csharp/tests/ConfigFileCredentialsProviderTest.cs
@@ -15,10 +15,11 @@
  * limitations under the License.
  */
 
-using Microsoft.VisualStudio.TestTools.UnitTesting;
 using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Org.Apache.Rocketmq;
 
-namespace Org.Apache.Rocketmq
+namespace tests
 {
     [TestClass]
     public class ConfigFileCredentialsProviderTest
@@ -27,14 +28,14 @@ namespace Org.Apache.Rocketmq
         public void Setup()
         {
             var configFilePath = ConfigFileCredentialsProvider.DefaultConfigFilePath();
-            FileInfo fileInfo = new FileInfo(configFilePath);
+            var fileInfo = new FileInfo(configFilePath);
             var dir = fileInfo.Directory;
-            if (!dir.Exists)
+            if (dir != null && !dir.Exists)
             {
                 dir.Create();
             }
 
-            string json = "{\"AccessKey\": \"key\", \"AccessSecret\": \"secret\"}";
+            var json = "{\"AccessKey\": \"key\", \"AccessSecret\": \"secret\"}";
             File.WriteAllText(configFilePath, json);
         }
         
diff --git a/csharp/tests/DateTimeTest.cs b/csharp/tests/DateTimeTest.cs
index 17bbd889..265e09e7 100644
--- a/csharp/tests/DateTimeTest.cs
+++ b/csharp/tests/DateTimeTest.cs
@@ -14,10 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+
 using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Org.Apache.Rocketmq;
 
-namespace Org.Apache.Rocketmq
+namespace tests
 {
 
     [TestClass]
@@ -25,11 +27,11 @@ namespace Org.Apache.Rocketmq
     {
 
         [TestMethod]
-        public void testFormat()
+        public void TestFormat()
         {
-            DateTime instant = new DateTime(2022, 02, 15, 08, 31, 56);
-            string time = instant.ToString(MetadataConstants.DateTimeFormat);
-            string expected = "20220215T083156Z";
+            var instant = new DateTime(2022, 02, 15, 08, 31, 56);
+            var time = instant.ToString(MetadataConstants.DateTimeFormat);
+            const string expected = "20220215T083156Z";
             Assert.AreEqual(time, expected);
         }
 
diff --git a/csharp/tests/EndpointsTest.cs b/csharp/tests/EndpointsTest.cs
index 6c4a6c71..4c85209e 100644
--- a/csharp/tests/EndpointsTest.cs
+++ b/csharp/tests/EndpointsTest.cs
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using Org.Apache.Rocketmq;
 
@@ -25,11 +24,19 @@ namespace tests
     public class EndpointsTest
     {
         [TestMethod]
-        public void testConstructor()
+        public void TestGrpcTargetWithoutSsl()
         {
-            Console.WriteLine(Uri.CheckHostName("127.0.0.1"));
-            Console.WriteLine(Uri.CheckHostName("1050:0000:0000:0000:0005:0600:300c:326b"));
-            Console.WriteLine(Uri.CheckHostName("baidu.com"));
+            var endpoints = new Endpoints("127.0.0.1");
+            var targetWithoutSsl = endpoints.GrpcTarget(false);
+            Assert.AreEqual("http://127.0.0.1:80", targetWithoutSsl);
+        }
+
+        [TestMethod]
+        public void TestGrpcTargetWithSsl()
+        {
+            var endpoints = new Endpoints("127.0.0.1");
+            var targetWithoutSsl = endpoints.GrpcTarget(true);
+            Assert.AreEqual("https://127.0.0.1:80", targetWithoutSsl);
         }
     }
 }
\ No newline at end of file
diff --git a/csharp/tests/MessageTest.cs b/csharp/tests/MessageTest.cs
index 7b28a6da..d8191d28 100644
--- a/csharp/tests/MessageTest.cs
+++ b/csharp/tests/MessageTest.cs
@@ -17,10 +17,11 @@
 
 using System;
 using System.Collections.Generic;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
 using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Org.Apache.Rocketmq;
 
-namespace Org.Apache.Rocketmq
+namespace tests
 {
     [TestClass]
     public class MessageTest
@@ -146,5 +147,22 @@ namespace Org.Apache.Rocketmq
         {
             new Message.Builder().SetKeys("a", "b");
         }
+
+        [TestMethod]
+        [ExpectedException(typeof(ArgumentException))]
+        public void TestSetDeliveryTimestampAndMessageGroup()
+        {
+            new Message.Builder().SetDeliveryTimestamp(DateTime.UtcNow + TimeSpan.FromSeconds(30))
+                .SetMessageGroup("messageGroup").Build();
+        }
+
+        [TestMethod]
+        [ExpectedException(typeof(ArgumentException))]
+        public void TestSetMessageGroupAndDeliveryTimestamp()
+        {
+            new Message.Builder().SetMessageGroup("messageGroup")
+                .SetDeliveryTimestamp(DateTime.UtcNow + TimeSpan.FromSeconds(30))
+                .Build();
+        }
     }
 }
\ No newline at end of file
diff --git a/csharp/tests/MqLogManagerTest.cs b/csharp/tests/MqLogManagerTest.cs
index 8a0e2c2a..076c9331 100644
--- a/csharp/tests/MqLogManagerTest.cs
+++ b/csharp/tests/MqLogManagerTest.cs
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using NLog;
diff --git a/csharp/tests/PublishingMessageTest.cs b/csharp/tests/PublishingMessageTest.cs
new file mode 100644
index 00000000..9f4938c0
--- /dev/null
+++ b/csharp/tests/PublishingMessageTest.cs
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Concurrent;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Org.Apache.Rocketmq;
+
+namespace tests
+{
+    [TestClass]
+    public class PublishingMessageTest
+    {
+        private const string ClientId = "fakeClientId";
+        private static readonly Endpoints Endpoints = new("127.0.0.1:8081");
+
+
+        [TestMethod]
+        public void TestNormalMessage()
+        {
+            const string topic = "yourNormalTopic";
+            var message = new Message.Builder().SetTopic(topic).SetBody(Encoding.UTF8.GetBytes("foobar")).Build();
+            var topics = new ConcurrentDictionary<string, bool>
+            {
+                [topic] = true
+            };
+            var settings = new PublishingSettings(ClientId, Endpoints,
+                ExponentialBackoffRetryPolicy.ImmediatelyRetryPolicy(3), TimeSpan.FromSeconds(3), topics);
+            var publishingMessage = new PublishingMessage(message, settings, false);
+            Assert.AreEqual(publishingMessage.MessageType, MessageType.Normal);
+        }
+
+        [TestMethod]
+        public void TestFifoMessage()
+        {
+            const string topic = "yourFifoTopic";
+            const string messageGroup = "yourMessageGroup";
+            var message = new Message.Builder().SetTopic(topic)
+                .SetMessageGroup(messageGroup).SetBody(Encoding.UTF8.GetBytes("foobar"))
+                .Build();
+            var topics = new ConcurrentDictionary<string, bool>
+            {
+                [topic] = true
+            };
+            var settings = new PublishingSettings(ClientId, Endpoints,
+                ExponentialBackoffRetryPolicy.ImmediatelyRetryPolicy(3), TimeSpan.FromSeconds(3), topics);
+            var publishingMessage = new PublishingMessage(message, settings, false);
+            Assert.AreEqual(publishingMessage.MessageType, MessageType.Fifo);
+        }
+
+        [TestMethod]
+        public void TestDelayMessage()
+        {
+            const string topic = "yourDelayTopic";
+            var message = new Message.Builder()
+                .SetTopic(topic)
+                .SetDeliveryTimestamp(DateTime.UtcNow + TimeSpan.FromSeconds(30))
+                .SetBody(Encoding.UTF8.GetBytes("foobar")).Build();
+            var topics = new ConcurrentDictionary<string, bool>
+            {
+                [topic] = true
+            };
+            var settings = new PublishingSettings(ClientId, Endpoints,
+                ExponentialBackoffRetryPolicy.ImmediatelyRetryPolicy(3),
+                TimeSpan.FromSeconds(3), topics);
+            var publishingMessage = new PublishingMessage(message, settings, false);
+            Assert.AreEqual(publishingMessage.MessageType, MessageType.Delay);
+        }
+
+        [TestMethod]
+        public void TestTransactionMessage()
+        {
+            const string topic = "yourTransactionMessage";
+            var message = new Message.Builder()
+                .SetTopic(topic)
+                .SetBody(Encoding.UTF8.GetBytes("foobar")).Build();
+            var topics = new ConcurrentDictionary<string, bool>
+            {
+                [topic] = true
+            };
+            var settings = new PublishingSettings(ClientId, Endpoints,
+                ExponentialBackoffRetryPolicy.ImmediatelyRetryPolicy(3),
+                TimeSpan.FromSeconds(3), topics);
+            var publishingMessage = new PublishingMessage(message, settings, true);
+            Assert.AreEqual(publishingMessage.MessageType, MessageType.Transaction);
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/tests/SendResultTest.cs b/csharp/tests/SendResultTest.cs
deleted file mode 100644
index 262410da..00000000
--- a/csharp/tests/SendResultTest.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace Org.Apache.Rocketmq
-{
-    [TestClass]
-    public class SendResultTest
-    {
-        [TestMethod]
-        public void testCtor()
-        {
-            // string messageId = new string("abc");
-            // var sendResult = new SendReceipt(messageId);
-            // Assert.AreEqual(messageId, sendResult.MessageId);
-        }
-    }
-}
\ No newline at end of file
diff --git a/csharp/tests/SignatureTest.cs b/csharp/tests/SignatureTest.cs
deleted file mode 100644
index 63b7cdf8..00000000
--- a/csharp/tests/SignatureTest.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using grpc = Grpc.Core;
-using Moq;
-using Org.Apache.Rocketmq;
-
-namespace tests
-{
-
-    [TestClass]
-    public class SignatureTest
-    {
-
-        [TestMethod]
-        public void TestSign()
-        {
-            // var mock = new Mock<IClientConfig>();
-            //
-            // string accessKey = "key";
-            // string accessSecret = "secret";
-            // var credentialsProvider = new StaticCredentialsProvider(accessKey, accessSecret);
-            //
-            // var metadata = new grpc::Metadata();
-            // Signature.Sign(mock.Object, metadata);
-            // Assert.IsNotNull(metadata.Get(MetadataConstants.Authorization));
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/csharp/tests/TopicTest.cs b/csharp/tests/TopicTest.cs
deleted file mode 100644
index 9f386dea..00000000
--- a/csharp/tests/TopicTest.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Collections.Generic;
-
-namespace Org.Apache.Rocketmq
-{
-
-    [TestClass]
-    public class TopicTest
-    {
-
-        [TestMethod]
-        public void testCompareTo()
-        {
-            List<Topic> topics = new List<Topic>();
-            topics.Add(new Topic("ns1", "t1"));
-            topics.Add(new Topic("ns0", "t1"));
-            topics.Add(new Topic("ns0", "t0"));
-
-            topics.Sort();
-
-            Assert.AreEqual(topics[0].ResourceNamespace, "ns0");
-            Assert.AreEqual(topics[0].Name, "t0");
-
-            Assert.AreEqual(topics[1].ResourceNamespace, "ns0");
-            Assert.AreEqual(topics[1].Name, "t1");
-
-
-            Assert.AreEqual(topics[2].ResourceNamespace, "ns1");
-            Assert.AreEqual(topics[2].Name, "t1");
-
-        }
-
-
-    }
-}
\ No newline at end of file
diff --git a/csharp/tests/UnitTest1.cs b/csharp/tests/UnitTest1.cs
deleted file mode 100644
index 2f6b468a..00000000
--- a/csharp/tests/UnitTest1.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.
- */
-
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Proto = Apache.Rocketmq.V2;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-
-namespace tests
-{
-    [TestClass]
-    public class UnitTest1
-    {
-        [TestMethod]
-        public void TestMethod1()
-        {
-            Proto::Permission perm = Proto::Permission.None;
-            switch (perm)
-            {
-                case Proto::Permission.None:
-                {
-                    Console.WriteLine("None");
-                    break;
-                }
-
-                case Proto::Permission.Read:
-                {
-                    Console.WriteLine("Read");
-                    break;
-                }
-
-                case Proto::Permission.Write:
-                {
-                    Console.WriteLine("Write");
-                    break;
-                }
-
-                case Proto::Permission.ReadWrite:
-                {
-                    Console.WriteLine("ReadWrite");
-                    break;
-                }
-            }
-        }
-
-        [TestMethod]
-        public void TestConcurrentDictionary()
-        {
-            var dict = new ConcurrentDictionary<string, List<String>>();
-            string s = "abc";
-            List<String> result;
-            var exists = dict.TryGetValue(s, out result);
-            Assert.IsFalse(exists);
-            Assert.IsNull(result);
-
-            result = new List<string>();
-            result.Add("abc");
-            Assert.IsTrue(dict.TryAdd(s, result));
-
-            List<String> list;
-            exists = dict.TryGetValue(s, out list);
-            Assert.IsTrue(exists);
-            Assert.IsNotNull(list);
-            Assert.AreEqual(1, list.Count);
-        }
-    }
-}
\ No newline at end of file
diff --git a/csharp/tests/tests.csproj b/csharp/tests/tests.csproj
index 578fe4e2..358b4a12 100644
--- a/csharp/tests/tests.csproj
+++ b/csharp/tests/tests.csproj
@@ -14,8 +14,8 @@
     <PackageReference Include="coverlet.collector" Version="3.0.2" />
   </ItemGroup>
 
-  <ItemGroup>
-    <ProjectReference Include="..\rocketmq-client-csharp\rocketmq-client-csharp.csproj" />
+  <ItemGroup>
+    <ProjectReference Include="..\rocketmq-client-csharp\rocketmq-client-csharp.csproj" />
   </ItemGroup>
 
 </Project>