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

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

commit 846304340c4407ce5839da30e8b4d9f3ea100153
Author: ShannonDing <[email protected]>
AuthorDate: Wed Jul 24 14:14:20 2019 +0800

    Add unit test case
---
 src/test/cpp/ApiTest.cpp           | 178 ++++++++++++++++++
 src/test/cpp/BaseTest.h            | 366 +++++++++++++++++++++++++++++++++++++
 src/test/cpp/CMakeLists.txt        |  21 +++
 src/test/cpp/ClientBaseTest.h      |  28 +++
 src/test/cpp/ConsumerTest.cpp      |  51 ++++++
 src/test/cpp/ExampleTest.cpp       |   7 +
 src/test/cpp/GraalThreadTest.cpp   |  21 +++
 src/test/cpp/LayoutTest.cpp        |  10 +
 src/test/cpp/LoggerTest.cpp        |   9 +
 src/test/cpp/OrderClientBaseTest.h |  26 +++
 src/test/cpp/OrderProducerTest.cpp |  71 +++++++
 src/test/cpp/ProducerTest.cpp      | 213 +++++++++++++++++++++
 src/test/cpp/PropertyTest.cpp      | 218 ++++++++++++++++++++++
 src/test/cpp/TestMain.cpp          |   6 +
 src/test/cpp/TransactionTest.cpp   |  87 +++++++++
 15 files changed, 1312 insertions(+)

diff --git a/src/test/cpp/ApiTest.cpp b/src/test/cpp/ApiTest.cpp
new file mode 100644
index 0000000..6efa832
--- /dev/null
+++ b/src/test/cpp/ApiTest.cpp
@@ -0,0 +1,178 @@
+#include <gtest/gtest.h>
+#include <iostream>
+#include "BaseTest.h"
+
+namespace ons {
+    class ApiTest : public BaseTest {
+    };
+
+    TEST_F(ApiTest, test_create_producer) {
+        int instance_id = create_producer(thread_, &property);
+        EXPECT_TRUE(instance_id >= 0) << "Instance Id should be non-negative";
+        destroy_instance(thread_, instance_id);
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, test_create_order_producer) {
+        int instance_id = create_order_producer(thread_, &property);
+        EXPECT_TRUE(instance_id >= 0) << "Instance Id should be non-negative";
+        destroy_instance(thread_, instance_id);
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, test_create_transaction_producer) {
+        void *transaction_check = (void *) transaction_check_func;
+        LocalTransactionCheckerImpl pTransactionCheckListener;
+        void *checker = reinterpret_cast<void *>(&pTransactionCheckListener);
+        int instance_id = create_transaction_producer(thread_, &property, 
checker, transaction_check);
+        EXPECT_TRUE(instance_id >= 0) << "Instance Id should be non-negative";
+        destroy_instance(thread_, instance_id);
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, test_create_consumer) {
+        int consumer_id = create_consumer(thread_, &property);
+        EXPECT_TRUE(consumer_id >= 0) << "Instance Id should be non-negative";
+        destroy_instance(thread_, consumer_id);
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, test_create_order_consumer) {
+        int consumer_id = create_order_consumer(thread_, &property);
+        EXPECT_TRUE(consumer_id >= 0) << "Instance Id should be non-negative";
+        destroy_instance(thread_, consumer_id);
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, test_send_message) {
+        int instance_id = create_producer(thread_, &property);
+        message m;
+        message_creator creator(m);
+        send_result sr;
+        send_result_wrapper wrapper(sr);
+        for (int i = 0; i < total; i++) {
+            send_message(thread_, instance_id, &m, &sr);
+            ASSERT_EQ(sr.error_no, 0);
+            std::cout << "Send OK, MsgId: " << sr.message_id << std::endl;
+        }
+        destroy_instance(thread_, instance_id);
+        std::cout << "Destroy instance OK" << std::endl;
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, test_send_message_oneway) {
+        int instance_id = create_producer(thread_, &property);
+        message m;
+        message_creator creator(m);
+        send_result sendResult;
+        send_result_wrapper wrapper(sendResult);
+        bzero(&sendResult, sizeof(send_result));
+        for (int i = 0; i < total; i++) {
+            send_message_oneway(thread_, instance_id, &m, &sendResult);
+        }
+        destroy_instance(thread_, instance_id);
+        std::cout << "Destroy instance OK" << std::endl;
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+        ASSERT_EQ(0, sendResult.error_no);
+    }
+
+    TEST_F(ApiTest, test_send_order_message) {
+        updatePropertyKeyValue("group_id", "GID_opensource_unit_test_order");
+        int instance_id = create_order_producer(thread_, &property);
+        message m;
+        message_creator creator(m, true);
+        send_result sr;
+        send_result_wrapper wrapper(sr);
+        char *sharding_key;
+        string_wrapper stringWrapper(sharding_key, "1");
+        for (int i = 0; i < total; i++) {
+            send_order_message(thread_, instance_id, &m, &sr, sharding_key);
+            ASSERT_EQ(sr.error_no, 0);
+            std::cout << "Send OK, MsgId: " << sr.message_id << std::endl;
+        }
+        destroy_instance(thread_, instance_id);
+        std::cout << "Destroy instance OK" << std::endl;
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, test_send_message_async) {
+        MyCallback pSendCallback;
+        int instance_id = create_producer(thread_, &property);
+        message m;
+        message_creator creator(m);
+        send_result sendResult;
+        send_result_wrapper wrapper(sendResult);
+        callback_func c_f;
+        c_f.on_success = on_success_func;
+        c_f.on_exception = on_exception_func;
+        c_f.send_callback_ons = reinterpret_cast<char *>(&pSendCallback);
+        for (int i = 0; i < MyCallback::message_num; i++) {
+            send_message_async(thread_, instance_id, &m, &sendResult, &c_f);
+        }
+        {
+            std::unique_lock<std::mutex> lk(m1);
+            cv.wait(lk);
+        }
+        destroy_instance(thread_, instance_id);
+        std::cout << "Destroy instance OK" << std::endl;
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, send_message_transaction) {
+        void *transaction_check = (void *) transaction_check_func;
+        LocalTransactionCheckerImpl pTransactionCheckListener;
+        void *checker = reinterpret_cast<void *>(&pTransactionCheckListener);
+        int instance_id = create_transaction_producer(thread_, &property, 
checker, transaction_check);
+        LocalTransactionExecuterImpl pTransactionExecutor;
+        message m;
+        message_creator creator(m);
+        send_result sr;
+        send_result_wrapper wrapper(sr);
+        void *executor = reinterpret_cast<void *>(&pTransactionExecutor);
+        void *transaction_execute = (void *) transaction_execute_func;
+        for (int i = 0; i < total; i++) {
+            send_message_transaction(thread_, instance_id, &m, &sr, executor, 
transaction_execute);
+            ASSERT_EQ(sr.error_no, 0);
+            std::cout << "Send OK, MsgId: " << sr.message_id << std::endl;
+        }
+        destroy_instance(thread_, instance_id);
+        std::cout << "Destroy instance OK" << std::endl;
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, subsribe) {
+        int instance_id = create_consumer(thread_, &property);
+        ExampleMessageListener messageListener;
+        ons::MessageListener *listener = &messageListener;
+        subscription sub;
+        memset(&sub, 0, sizeof(subscription));
+        subscribe_creator creator(sub, "t_opensource_unit_test", "*");
+        sub.opaque = listener;
+        sub.on_message = consumer_on_message;
+        ::subscribe(thread_, instance_id, &sub);
+        start_instance(thread_, instance_id);
+        std::this_thread::sleep_for(std::chrono::milliseconds(20 * 1000));
+        destroy_instance(thread_, instance_id);
+        std::cout << "Destroy instance OK" << std::endl;
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+    TEST_F(ApiTest, subsribe_order) {
+        updatePropertyKeyValue("group_id", "GID_opensource_unit_test_order");
+        int instance_id = create_order_consumer(thread_, &property);
+        ExampleMessageOrderListener messageOrderListener;
+        ons::MessageOrderListener *listener = &messageOrderListener;
+        subscription sub;
+        memset(&sub, 0, sizeof(subscription));
+        subscribe_creator creator(sub, "t_opensource_unit_test_order", "tagA");
+        sub.opaque = listener;
+        sub.on_message = order_consumer_on_message;
+        subscribe_order_listener(thread_, instance_id, &sub);
+        start_instance(thread_, instance_id);
+        std::this_thread::sleep_for(std::chrono::milliseconds(60 * 1000));
+        destroy_instance(thread_, instance_id);
+        std::cout << "Destroy instance OK" << std::endl;
+        ASSERT_EQ(graal_detach_thread(thread_), 0) << "Detach graal thread 
failed";
+    }
+
+}  // namespace ons
diff --git a/src/test/cpp/BaseTest.h b/src/test/cpp/BaseTest.h
new file mode 100644
index 0000000..a87fe29
--- /dev/null
+++ b/src/test/cpp/BaseTest.h
@@ -0,0 +1,366 @@
+#ifndef MQ_BASE_TEST_H
+#define MQ_BASE_TEST_H
+
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+
+
+#include "rocketmq.h"
+#include "rocketmq-ons-cpp-full.h"
+#include "ONSCallback.h"
+#include "Message.h"
+#include "UtilAll.h"
+#include "Common.h"
+
+
+namespace ons {
+    class send_result_wrapper {
+    public:
+        send_result_wrapper(send_result &sendResult) : sendResult_(sendResult) 
{
+            memset(&sendResult, 0, sizeof(sendResult));
+            sendResult.message_id = new char[ONS_SEND_RESULT_MSG_ID_LEN_MAX + 
1];
+            memset(sendResult.message_id, 0, ONS_SEND_RESULT_MSG_ID_LEN_MAX + 
1);
+            sendResult.error_msg = new char[ONS_SEND_RESULT_ERR_MSG_LEN_MAX + 
1];
+            memset(sendResult.error_msg, 0, ONS_SEND_RESULT_ERR_MSG_LEN_MAX + 
1);
+        }
+
+        ~send_result_wrapper() {
+            delete[](sendResult_.message_id);
+            delete[](sendResult_.error_msg);
+        }
+
+    private:
+        send_result &sendResult_;
+    };
+
+    class message_creator {
+    public:
+        message_creator(message &m, bool is_order = false) : m_(m) {
+            memset(&m, 0, sizeof(m));
+
+            if (!is_order) {
+                const char *topic = "t_opensource_unit_test";
+                m.topic = new char[strlen(topic) + 1];
+                strcpy(m.topic, topic);
+            } else {
+                const char *topic_ = "t_opensource_unit_test_order";
+                m.topic = new char[strlen(topic_) + 1];
+                strcpy(m.topic, topic_);
+            }
+
+            const char *tag = "tagA";
+            m.tags = new char[strlen(tag) + 1];
+            strcpy(m.tags, tag);
+
+            const char *body = "Sample message body content";
+            m.body = new char[strlen(body) + 1];
+            strcpy(m.body, body);
+            m.body_size = strlen(m.body);
+
+
+            const char *key = "abc";
+            m.key = new char[strlen(key) + 1];
+            strcpy(m.key, key);
+
+            const char *props = "{}";
+            m.user_prop = new char[strlen(props) + 1];
+            strcpy(m.user_prop, props);
+
+            m.system_prop = new char[strlen(props) + 1];
+            strcpy(m.system_prop, props);
+        }
+
+        ~message_creator() {
+            delete[](m_.topic);
+            delete[](m_.tags);
+            delete[](m_.body);
+            delete[](m_.key);
+            delete[](m_.user_prop);
+            delete[](m_.system_prop);
+        }
+
+    private:
+        message &m_;
+    };
+
+    class subscribe_creator {
+    public:
+        subscribe_creator(subscription &sub,const char *topic, const char 
*sub_expression):sub_(sub) {
+            sub.topic = new char[strlen(topic) + 1];
+            strcpy(sub.topic, topic);
+
+            sub.sub_expression = new char[strlen(sub_expression) + 1];
+            strcpy(sub.sub_expression, sub_expression);
+        }
+
+        ~subscribe_creator() {
+            delete[](sub_.topic);
+            delete[](sub_.sub_expression);
+        }
+
+    private:
+        subscription &sub_;
+    };
+    class string_wrapper {
+    public:
+        string_wrapper(char* &str,const char* value) : str_(str) {
+            str = new char[strlen(value) + 1];
+            strcpy(str, value);
+        }
+
+        ~string_wrapper() {
+            delete str_;
+        }
+
+    private:
+        char* &str_;
+    };
+    class BaseTest : public ::testing::Test {
+    protected:
+        BaseTest() {}
+
+        void SetUp() override {
+            int create_isolate_status = graal_create_isolate(NULL, &isolate_, 
&thread_);
+            ASSERT_EQ(create_isolate_status, 0) << "error on isolate creation 
or attach";
+
+            memset(&property, 0, sizeof(factory_property));
+            const char *group_id = "GID_opensource_unit_test";
+            const char *access_key = "AK";
+            const char *access_secret = "SK";
+            const char *name_srv_addr = "47.100.33.127:9876";
+            group_id_ = new char[strlen(group_id) + 1];
+            strcpy(group_id_, group_id);
+            property.group_id = group_id_;
+
+            access_key_ = new char[strlen(access_key) + 1];
+            strcpy(access_key_, access_key);
+            property.access_key = access_key_;
+
+            access_secret_ = new char[strlen(access_secret) + 1];
+            strcpy(access_secret_, access_secret);
+            property.access_secret = access_secret_;
+
+            name_srv_addr_ = new char[strlen(name_srv_addr) + 1];
+            strcpy(name_srv_addr_, name_srv_addr);
+            property.name_srv_addr = name_srv_addr_;
+
+            total = 32;
+        }
+
+        void TearDown() override {
+            delete group_id_;
+            group_id_ = NULL;
+            delete access_key_;
+            access_key_ = NULL;
+            delete access_secret_;
+            access_secret_ = NULL;
+            delete name_srv_addr_;
+            name_srv_addr_ = NULL;
+        }
+
+        void updatePropertyKeyValue(const char *key, const char *value) {
+            if (0 == strcasecmp(key, "group_id")) {
+                if (group_id_ != NULL) {
+                    delete group_id_;
+                    group_id_ = NULL;
+                }
+                group_id_ = new char[strlen(value) + 1];
+                strcpy(group_id_, value);
+                property.group_id = group_id_;
+            }
+            if (0 == strcasecmp(key, "access_key")) {
+                if (access_key_ != NULL) {
+                    delete access_key_;
+                    access_key_ = NULL;
+                }
+                access_key_ = new char[strlen(value) + 1];
+                strcpy(access_key_, value);
+                property.access_key = access_key_;
+            }
+            if (0 == strcasecmp(key, "access_secret")) {
+                if (access_secret_ != NULL) {
+                    delete access_secret_;
+                    access_secret_ = NULL;
+                }
+                access_secret_ = new char[strlen(value) + 1];
+                strcpy(access_secret_, value);
+                property.access_secret = access_secret_;
+            }
+            if (0 == strcasecmp(key, "name_srv_addr")) {
+                if (name_srv_addr_ != NULL) {
+                    delete name_srv_addr_;
+                    name_srv_addr_ = NULL;
+                }
+                name_srv_addr_ = new char[strlen(value) + 1];
+                strcpy(name_srv_addr_, value);
+                property.name_srv_addr = name_srv_addr_;
+            }
+        }
+
+        graal_isolate_t *isolate_;
+        graal_isolatethread_t *thread_;
+        char *group_id_;
+        char *access_key_;
+        char *access_secret_;
+        char *name_srv_addr_;
+        factory_property property;
+        int total;
+    };
+
+    std::mutex m1;
+    std::mutex m2;
+    std::condition_variable cv;
+
+    class MyCallback : public ons::SendCallbackONS {
+    public:
+        void onSuccess(ons::SendResultONS &sendResult) override {
+            std::lock_guard<std::mutex> lg(m2);
+            success_num++;
+            std::cout << "send success, message_id: " << 
sendResult.getMessageId() << ", total: " << success_num
+                      << std::endl;
+            if (success_num + failed_num == message_num) {
+                cv.notify_all();
+            }
+        }
+
+        void onException(ons::ONSClientException &e) override {
+            std::lock_guard<std::mutex> lg(m2);
+            failed_num++;
+            std::cout << "send failure, total: " << failed_num << std::endl;
+            std::cout << e.what() << std::endl;
+            if (success_num + failed_num == message_num) {
+                cv.notify_all();
+            }
+        }
+
+        static int success_num;
+        static int failed_num;
+        static int message_num;
+    };
+
+    int MyCallback::success_num = 0;
+    int MyCallback::failed_num = 0;
+    int MyCallback::message_num = 32;
+
+    class LocalTransactionCheckerImpl : public ons::LocalTransactionChecker {
+        virtual ons::TransactionStatus check(ons::Message &msg) {
+            cout << "checker::commit transaction" << endl;
+            return ons::CommitTransaction;
+        }
+    };
+
+    class LocalTransactionExecuterImpl : public ons::LocalTransactionExecuter {
+        virtual ons::TransactionStatus execute(ons::Message &msg) {
+            cout << "executer::commit transaction of msgid: " << 
msg.getMsgID() << endl;
+            return ons::CommitTransaction;
+        }
+    };
+
+    std::mutex console_mtx;
+
+    class ExampleMessageListener : public ons::MessageListener {
+    public:
+        Action consume(ons::Message &message, ons::ConsumeContext &context) {
+            std::lock_guard<std::mutex> lk(console_mtx);
+            std::cout << "Received a message. Topic: " << message.getTopic() 
<< ", MsgId: "
+                      << message.getMsgID() << std::endl;
+            return CommitMessage;
+        }
+    };
+
+    class ExampleMessageOrderListener : public ons::MessageOrderListener {
+    public:
+        OrderAction consume(ons::Message &message, ons::ConsumeOrderContext 
&context) {
+            std::lock_guard<std::mutex> lk(console_mtx);
+            std::cout << "Received a message. Topic: " << message.getTopic() 
<< ", MsgId: "
+                      << message.getMsgID() << std::endl;
+            return Success;
+        }
+    };
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+    void on_success_func(void *thread, char *message_id, char 
*send_callback_ons) {
+        auto sendCallbackONS = reinterpret_cast<ons::SendCallbackONS 
*>(send_callback_ons);
+        ons::SendResultONS sendResultOns;
+        sendResultOns.setMessageId(message_id);
+        sendCallbackONS->onSuccess(sendResultOns);
+    }
+
+    void on_exception_func(void *thread, char *m_msg, int m_error, char 
*send_callback_ons) {
+        auto sendCallbackONS = reinterpret_cast<ons::SendCallbackONS 
*>(send_callback_ons);
+        ons::ONSClientException onsClientException(m_msg, m_error);
+        sendCallbackONS->onException(onsClientException);
+    }
+
+    int transaction_check_func(void *thread, void *opaque, char *topic, char 
*user_props, char *sys_props,
+                               char *body, int body_len) {
+        ons::LocalTransactionChecker *checker = 
reinterpret_cast<ons::LocalTransactionChecker *>(opaque);
+        ons::Message message_;
+        message_.setTopic(topic);
+        ons::UtilAll::fill_message_props(message_, std::string(user_props), 
false);
+        ons::UtilAll::fill_message_props(message_, std::string(sys_props), 
true);
+        message_.setBody(reinterpret_cast<unsigned char *>(body), body_len);
+        return checker->check(message_);
+    }
+
+    int transaction_execute_func(void *thread, void *opaque, char *topic, char 
*user_props, char *sys_props,
+                                 char *body, int body_len) {
+        ons::LocalTransactionExecuter *executor = 
reinterpret_cast<ons::LocalTransactionExecuter *>(opaque);
+        ons::Message message_;
+        message_.setTopic(topic);
+        ons::UtilAll::fill_message_props(message_, std::string(user_props), 
false);
+        ons::UtilAll::fill_message_props(message_, std::string(sys_props), 
true);
+        message_.setBody(reinterpret_cast<unsigned char *>(body), body_len);
+        return executor->execute(message_);
+    }
+
+    int consumer_on_message(void *thread, void *opaque, char *topic, char 
*user_props, char *sys_props, char *body,
+                            int body_len) {
+        ons::MessageListener *listener = reinterpret_cast<ons::MessageListener 
*>(opaque);
+        ons::Message message_;
+        message_.setTopic(topic);
+        ons::UtilAll::fill_message_props(message_, std::string(user_props), 
false);
+        ons::UtilAll::fill_message_props(message_, std::string(sys_props), 
true);
+        message_.setBody(reinterpret_cast<unsigned char *>(body), body_len);
+        ons::ConsumeContext ctx_;
+        Action action = listener->consume(message_, ctx_);
+        switch (action) {
+            case CommitMessage:
+                return 0;
+            case ReconsumeLater:
+                return 1;
+            default:
+                return 1;
+        }
+    }
+
+    int
+    order_consumer_on_message(void *thread, void *opaque, char *topic, char 
*user_props, char *sys_props, char *body,
+                              int body_len) {
+        ons::MessageOrderListener *listener = 
reinterpret_cast<ons::MessageOrderListener *>(opaque);
+        ons::Message message_;
+        message_.setTopic(topic);
+        ons::UtilAll::fill_message_props(message_, std::string(user_props), 
false);
+        ons::UtilAll::fill_message_props(message_, std::string(sys_props), 
true);
+        message_.setBody(reinterpret_cast<unsigned char *>(body), body_len);
+        ons::ConsumeOrderContext ctx_;
+        OrderAction action = listener->consume(message_, ctx_);
+        switch (action) {
+            case Success:
+                return 0;
+            case Suspend:
+                return 1;
+            default:
+                return 1;
+        }
+    }
+#ifdef __cplusplus
+    }
+#endif
+
+}  // namespace ons
+
+#endif  // MQ_BASE_TEST_H
diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt
new file mode 100644
index 0000000..2a79268
--- /dev/null
+++ b/src/test/cpp/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(${CMAKE_SOURCE_DIR}/src/test/cpp
+                    ${CMAKE_SOURCE_DIR}/src/main/cpp/sdk)
+
+macro(add_gtest test_name test_source)
+    add_executable(${test_name} ${test_source} TestMain.cpp)
+    target_link_libraries(${test_name} gtest ${LIBRARY_NAME})
+    add_test(NAME ${test_name} COMMAND ${test_name})
+    set_target_properties(${test_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY 
${PROJECT_BINARY_DIR}/tests)
+endmacro()
+
+add_gtest(example_test ExampleTest.cpp)
+add_gtest(graal_thread_test GraalThreadTest.cpp)
+add_gtest(api_test ApiTest.cpp)
+add_gtest(logger_test LoggerTest.cpp)
+add_gtest(layout_test LayoutTest.cpp)
+add_gtest(producer_test ProducerTest.cpp)
+#add_gtest(property_test PropertyTest.cpp)
+add_gtest(trasaction_test TransactionTest.cpp)
+add_gtest(order_producer_test OrderProducerTest.cpp)
+add_gtest(message_test MessageTest.cpp)
+add_gtest(consumer_test ConsumerTest.cpp)
diff --git a/src/test/cpp/ClientBaseTest.h b/src/test/cpp/ClientBaseTest.h
new file mode 100644
index 0000000..797e20f
--- /dev/null
+++ b/src/test/cpp/ClientBaseTest.h
@@ -0,0 +1,28 @@
+#ifndef MQ_CLIENT_BASE_TEST_H
+#define MQ_CLIENT_BASE_TEST_H
+
+#include <iostream>
+
+#include "ONSFactory.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+class ClientBaseTest : public testing::Test {
+protected:
+    void SetUp() override {
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test");
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ConsumerId, 
"GID_opensource_unit_test");
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::GroupId, 
"GID_opensource_unit_test");
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, 
"AK");
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, 
"SK");
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR, 
"47.100.33.127:9876");
+    }
+
+    void TearDown() override {
+    }
+
+    ons::ONSFactoryProperty factoryInfo;
+};
+
+#endif //MQ_CLIENT_BASE_TEST_H
diff --git a/src/test/cpp/ConsumerTest.cpp b/src/test/cpp/ConsumerTest.cpp
new file mode 100644
index 0000000..9da6f27
--- /dev/null
+++ b/src/test/cpp/ConsumerTest.cpp
@@ -0,0 +1,51 @@
+#include <iostream>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "ClientBaseTest.h"
+
+using namespace ons;
+
+class UnitTestMessageListener : public MessageListener {
+public:
+    Action consume(Message &message, ConsumeContext &context) {
+        return CommitMessage;
+    }
+};
+
+class ConsumerTest : public ClientBaseTest {
+protected:
+    void SetUp() override {
+        ClientBaseTest::SetUp();
+        consumer_ = 
ons::ONSFactory::getInstance()->createPushConsumer(factoryInfo);
+        messageListener_ = new UnitTestMessageListener();
+    }
+
+    void TearDown() override {
+        ClientBaseTest::TearDown();
+        //consumer_->shutdown();
+        delete messageListener_;
+    }
+
+    ons::PushConsumer *consumer_;
+    const char *topic_ = "Topic";
+    const char *tag_ = "Tag";
+    UnitTestMessageListener *messageListener_;
+};
+
+TEST_F(ConsumerTest, test_setUp) {
+    ASSERT_TRUE(nullptr != consumer_);
+}
+
+TEST_F(ConsumerTest, testSubscriber_topicBeingNull) {
+    EXPECT_THROW(consumer_->subscribe(NULL, tag_, messageListener_);, 
ons::ONSClientException);
+}
+
+TEST_F(ConsumerTest, testSubscriber_tagBeingNull) {
+    EXPECT_THROW(consumer_->subscribe(topic_, NULL, messageListener_);, 
ons::ONSClientException);
+}
+
+TEST_F(ConsumerTest, testSubscriber_ListenerBeingNull) {
+    EXPECT_THROW(consumer_->subscribe(topic_, tag_, NULL);, 
ons::ONSClientException);
+}
diff --git a/src/test/cpp/ExampleTest.cpp b/src/test/cpp/ExampleTest.cpp
new file mode 100644
index 0000000..f30d759
--- /dev/null
+++ b/src/test/cpp/ExampleTest.cpp
@@ -0,0 +1,7 @@
+#include <gtest/gtest.h>
+
+TEST(ExampleTest, testSetUp) {
+    int a = 1;
+    int b = 1;
+    ASSERT_EQ(a, b);
+}
\ No newline at end of file
diff --git a/src/test/cpp/GraalThreadTest.cpp b/src/test/cpp/GraalThreadTest.cpp
new file mode 100644
index 0000000..3e3d44f
--- /dev/null
+++ b/src/test/cpp/GraalThreadTest.cpp
@@ -0,0 +1,21 @@
+#include "ClientBase.h"
+#include <gtest/gtest.h>
+
+using namespace ons;
+
+class SampleClient : ClientBase {
+public:
+    SampleClient() {
+
+    }
+
+    ~SampleClient() {
+
+    }
+
+};
+
+TEST(GraalThreadTest, testAttach_Detach) {
+    SampleClient *sample = new SampleClient();
+    delete sample;
+}
\ No newline at end of file
diff --git a/src/test/cpp/LayoutTest.cpp b/src/test/cpp/LayoutTest.cpp
new file mode 100644
index 0000000..b098cc7
--- /dev/null
+++ b/src/test/cpp/LayoutTest.cpp
@@ -0,0 +1,10 @@
+#include <type_traits>
+#include <gtest/gtest.h>
+#include "rocketmq.h"
+
+TEST(LayoutTest, testIsStandardLayout) {
+    ASSERT_TRUE(std::is_standard_layout<message>::value);
+    ASSERT_TRUE(std::is_standard_layout<send_result>::value);
+    ASSERT_TRUE(std::is_standard_layout<factory_property>::value);
+    ASSERT_TRUE(std::is_standard_layout<message>::value);
+}
\ No newline at end of file
diff --git a/src/test/cpp/LoggerTest.cpp b/src/test/cpp/LoggerTest.cpp
new file mode 100644
index 0000000..8e9d1cb
--- /dev/null
+++ b/src/test/cpp/LoggerTest.cpp
@@ -0,0 +1,9 @@
+#include <gtest/gtest.h>
+#include "Logger.h"
+
+//std::once_flag rocketmq::spd_log::once_log_flag;
+
+TEST(LoggerTest, testLog) {
+    rocketmq::spd_log::initLogger();
+    spdlog::debug("This is a debug line");
+}
\ No newline at end of file
diff --git a/src/test/cpp/OrderClientBaseTest.h 
b/src/test/cpp/OrderClientBaseTest.h
new file mode 100644
index 0000000..5a7765b
--- /dev/null
+++ b/src/test/cpp/OrderClientBaseTest.h
@@ -0,0 +1,26 @@
+#ifndef MQ_CLIENT_BASE_TEST_H
+#define MQ_CLIENT_BASE_TEST_H
+
+#include <iostream>
+
+#include "ONSFactory.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+class OrderClientBaseTest : public testing::Test {
+protected:
+    void SetUp() override {
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test_order");
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, 
"AK");
+        factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, 
"SK");
+        
factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,"47.100.33.127:9876");
+    }
+
+    void TearDown() override {
+    }
+
+    ons::ONSFactoryProperty factoryInfo;
+};
+
+#endif //MQ_CLIENT_BASE_TEST_H
diff --git a/src/test/cpp/OrderProducerTest.cpp 
b/src/test/cpp/OrderProducerTest.cpp
new file mode 100644
index 0000000..7fe2bb6
--- /dev/null
+++ b/src/test/cpp/OrderProducerTest.cpp
@@ -0,0 +1,71 @@
+#include <iostream>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <memory>
+
+#include <mutex>
+#include <thread>
+#include <condition_variable>
+
+#include "OrderClientBaseTest.h"
+
+class OrderProducerTest : public OrderClientBaseTest {
+protected:
+    void SetUp() override {
+        OrderClientBaseTest::SetUp();
+        producer_ = 
ons::ONSFactory::getInstance()->createOrderProducer(factoryInfo);
+        producer_->start();
+    }
+
+    void TearDown() override {
+        OrderClientBaseTest::TearDown();
+        producer_->shutdown();
+    }
+
+    ons::OrderProducer *producer_;
+};
+
+TEST_F(OrderProducerTest, test_setUp) {
+    ASSERT_TRUE(nullptr != producer_);
+}
+
+TEST_F(OrderProducerTest, testSendMessage_Normal) {
+    ons::Message msg(
+            "t_opensource_unit_test_order",
+            "tagA",
+            "ORDERID_100",
+            "hello, RocketMQ."
+    );
+    ons::SendResultONS sendResult = producer_->send(msg, "1");
+    ASSERT_TRUE(nullptr != sendResult.getMessageId());
+}
+
+TEST_F(OrderProducerTest, testSendMessage_TopicBeingEmpty) {
+    ons::Message msg(
+            "",
+            "tagA",
+            "ORDERID_100",
+            "hello Order Message."
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg, "1"), 
ons::ONSClientException);
+}
+
+TEST_F(OrderProducerTest, testSendMessage_TopicNotExist) {
+    ons::Message msg(
+            "topic_not_use_test",
+            "tagA",
+            "ORDERID_100",
+            "hello Order Message."
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg, "1"), 
ons::ONSClientException);
+}
+
+TEST_F(OrderProducerTest, testSendMessage_BodyBeingEmpty) {
+    ons::Message msg(
+            "t_opensource_unit_test_order",
+            "tagA",
+            "ORDERID_100",
+            ""
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg, "1"), 
ons::ONSClientException);
+}
\ No newline at end of file
diff --git a/src/test/cpp/ProducerTest.cpp b/src/test/cpp/ProducerTest.cpp
new file mode 100644
index 0000000..8687c91
--- /dev/null
+++ b/src/test/cpp/ProducerTest.cpp
@@ -0,0 +1,213 @@
+#include <iostream>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <memory>
+
+#include <mutex>
+#include <thread>
+#include <condition_variable>
+
+#include "ClientBaseTest.h"
+
+class ProducerTest : public ClientBaseTest {
+protected:
+    void SetUp() override {
+        ClientBaseTest::SetUp();
+        producer_ = 
ons::ONSFactory::getInstance()->createProducer(factoryInfo);
+        producer_->start();
+    }
+
+    void TearDown() override {
+        ClientBaseTest::TearDown();
+        producer_->shutdown();
+    }
+
+    ons::Producer *producer_;
+};
+
+TEST_F(ProducerTest, test_setUp) {
+    ASSERT_TRUE(nullptr != producer_);
+}
+
+TEST_F(ProducerTest, testSendMessage_Normal) {
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            "hello RocketMQ."
+    );
+    ons::SendResultONS sendResult = producer_->send(msg);
+    ASSERT_TRUE(nullptr != sendResult.getMessageId());
+}
+
+TEST_F(ProducerTest, testSendMessage_TopicBeingEmpty) {
+    ons::Message msg(
+            "",
+            "tagA",
+            "ORDERID_100",
+            "hello RocketMQ."
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg), 
ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessage_TopicBeingNULL) {
+    EXPECT_THROW(
+            ons::Message msg(NULL, "tagA", "ORDERID_100", "hello RocketMQ.");,
+            ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessage_TopicNotExist) {
+    ons::Message msg(
+            "topic_not_use_test",
+            "tagA",
+            "ORDERID_100",
+            "hello RocketMQ."
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg), 
ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessage_BodyBeingEmpty) {
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            ""
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg), 
ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessageOneway_Normal) {
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            "hello RocketMQ."
+    );
+    EXPECT_NO_THROW(producer_->sendOneway(msg));
+}
+
+TEST_F(ProducerTest, testSendMessageOneway_TopicBeingEmpty) {
+    ons::Message msg(
+            "",
+            "tagA",
+            "ORDERID_100",
+            "hello RocketMQ."
+    );
+    EXPECT_THROW(producer_->sendOneway(msg), ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessageOneway_TopicNotExist) {
+    ons::Message msg(
+            "topic_not_use_test",
+            "tagA",
+            "ORDERID_100",
+            "hello MQ_lingchu"
+    );
+    EXPECT_THROW(producer_->sendOneway(msg), ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessageOneway_BodyBeingEmpty) {
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            ""
+    );
+    EXPECT_THROW(producer_->sendOneway(msg), ons::ONSClientException);
+}
+
+class ExampleSendCallback : public ons::SendCallbackONS {
+public:
+    ExampleSendCallback(std::mutex &mtx, bool &complete, 
std::condition_variable &cv, bool &success)
+            : mtx_(mtx), complete_(complete), cv_(cv), success_(success) {
+    }
+
+    void onSuccess(ons::SendResultONS &sendResult) override {
+        success_ = true;
+        {
+            std::unique_lock<std::mutex> lk(mtx_);
+            complete_ = true;
+        }
+        cv_.notify_all();
+    };
+
+    virtual void onException(ons::ONSClientException &e) override {
+        {
+            std::unique_lock<std::mutex> lk(mtx_);
+            complete_ = true;
+        }
+        cv_.notify_all();
+    };
+
+    std::mutex &mtx_;
+    bool &complete_;
+    std::condition_variable &cv_;
+    bool &success_;
+};
+
+TEST_F(ProducerTest, testSendMessageAsync_Normal) {
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            "hello RocketMQ."
+    );
+    std::mutex mtx;
+    std::condition_variable cv;
+    bool complete = false;
+    bool success = false;
+    ExampleSendCallback cb(mtx, complete, cv, success);
+    producer_->sendAsync(msg, &cb);
+
+    {
+        std::unique_lock<std::mutex> lk(mtx);
+        cv.wait(lk, [&]() { return complete; });
+    }
+
+    ASSERT_TRUE(success);
+}
+
+TEST_F(ProducerTest, testSendMessageAsync_TopicBeingEmpty) {
+    ons::Message msg(
+            "",
+            "tagA",
+            "ORDERID_100",
+            "hello RocketMQ."
+    );
+    std::mutex mtx;
+    std::condition_variable cv;
+    bool complete = false;
+    bool success = false;
+    ExampleSendCallback cb(mtx, complete, cv, success);
+    EXPECT_THROW(producer_->sendAsync(msg, &cb);, ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessageAsync_BodyBeingEmpty) {
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            ""
+    );
+    std::mutex mtx;
+    std::condition_variable cv;
+    bool complete = false;
+    bool success = false;
+    ExampleSendCallback cb(mtx, complete, cv, success);
+    EXPECT_THROW(producer_->sendAsync(msg, &cb);, ons::ONSClientException);
+}
+
+TEST_F(ProducerTest, testSendMessageAsync_TopicNotExist) {
+    ons::Message msg(
+            "topic_not_use_test",
+            "tagA",
+            "ORDERID_100",
+            "Hello, RocketMQ"
+    );
+    std::mutex mtx;
+    std::condition_variable cv;
+    bool complete = false;
+    bool success = false;
+    ExampleSendCallback cb(mtx, complete, cv, success);
+    EXPECT_THROW(producer_->sendAsync(msg, &cb);, ons::ONSClientException);
+}
\ No newline at end of file
diff --git a/src/test/cpp/PropertyTest.cpp b/src/test/cpp/PropertyTest.cpp
new file mode 100644
index 0000000..778df2e
--- /dev/null
+++ b/src/test/cpp/PropertyTest.cpp
@@ -0,0 +1,218 @@
+#include <iostream>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <memory>
+#include "ONSFactory.h"
+
+
+class PropertyTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+    }
+
+    void TearDown() override {
+    }
+};
+
+TEST_F(PropertyTest, testSendMessage_AkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::Producer *producer_ = 
ons::ONSFactory::getInstance()->createProducer(factoryInfo);,
+            ons::ONSClientException);
+}
+
+TEST_F(PropertyTest, testSendMessage_AkBeingWrong) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    ons::Producer *producer_ = 
ons::ONSFactory::getInstance()->createProducer(factoryInfo);
+    ASSERT_TRUE(nullptr != producer_);
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            "Hello RocketMQ"
+    );
+    EXPECT_THROW(ons::SendResultONS
+                         sendResult = producer_->send(msg), 
ons::ONSClientException);
+    producer_->shutdown();
+}
+
+TEST_F(PropertyTest, testSendMessage_SkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::Producer *producer_ = 
ons::ONSFactory::getInstance()->createProducer(factoryInfo);,
+            ons::ONSClientException);
+}
+
+TEST_F(PropertyTest, testSendMessage_SkBeingWrong) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GIDt_opensource_unit_test");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    ons::Producer *producer_ = 
ons::ONSFactory::getInstance()->createProducer(factoryInfo);
+    ASSERT_TRUE(nullptr != producer_);
+    ons::Message msg(
+            "t_opensource_unit_test",
+            "tagA",
+            "ORDERID_100",
+            "Hello RocketMQ"
+    );
+    EXPECT_THROW(ons::SendResultONS
+                         sendResult = producer_->send(msg), 
ons::ONSClientException);
+    producer_->shutdown();
+}
+
+TEST_F(PropertyTest, testSendOrderMessage_AkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_shutian_order_test");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::OrderProducer *producer_ = 
ons::ONSFactory::getInstance()->createOrderProducer(factoryInfo);,
+            ons::ONSClientException);
+}
+
+TEST_F(PropertyTest, testSendOrderMessage_AkBeingWrong) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    ons::OrderProducer *producer_ = 
ons::ONSFactory::getInstance()->createOrderProducer(factoryInfo);
+    ASSERT_TRUE(nullptr != producer_);
+    ons::Message msg(
+            "t_opensource_unit_test_order",
+            "tagA",
+            "ORDERID_100",
+            "Hello RocketMQ"
+    );
+    string sharding_key = "1";
+    EXPECT_THROW(ons::SendResultONS
+                         sendResult = producer_->send(msg, sharding_key), 
ons::ONSClientException);
+    producer_->shutdown();
+}
+
+TEST_F(PropertyTest, testSendOrderMessage_SkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::OrderProducer *producer_ = 
ons::ONSFactory::getInstance()->createOrderProducer(factoryInfo);,
+            ons::ONSClientException);
+}
+
+TEST_F(PropertyTest, testSendOrderMessage_SkBeingWrong) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    ons::OrderProducer *producer_ = 
ons::ONSFactory::getInstance()->createOrderProducer(factoryInfo);
+    ASSERT_TRUE(nullptr != producer_);
+    ons::Message msg(
+            "t_opensource_unit_test_order",
+            "tagA",
+            "ORDERID_100",
+            "Hello RocketMQ"
+    );
+    string sharding_key = "1";
+    EXPECT_THROW(ons::SendResultONS
+                         sendResult = producer_->send(msg, sharding_key), 
ons::ONSClientException);
+    producer_->shutdown();
+}
+
+TEST_F(PropertyTest, testSendTransactionMessage_AkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::TransactionProducer *producer_ = 
ons::ONSFactory::getInstance()->createTransactionProducer(factoryInfo,NULL);,
+            ons::ONSClientException);
+}
+
+TEST_F(PropertyTest, testSendTransactionMessage_SkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ProducerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::TransactionProducer *producer_ = 
ons::ONSFactory::getInstance()->createTransactionProducer(factoryInfo,NULL);,
+            ons::ONSClientException);
+}
+
+TEST_F(PropertyTest, testPushConsumer_AkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ConsumerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::PushConsumer *consumer_ = 
ons::ONSFactory::getInstance()->createPushConsumer(factoryInfo);,
+            ons::ONSClientException);
+}
+TEST_F(PropertyTest, testPushConsumer_SkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ConsumerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::PushConsumer *consumer_ = 
ons::ONSFactory::getInstance()->createPushConsumer(factoryInfo);,
+            ons::ONSClientException);
+}
+TEST_F(PropertyTest, testOrderConsumer_AkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ConsumerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::SecretKey, "SK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::OrderConsumer *consumer_ = 
ons::ONSFactory::getInstance()->createOrderConsumer(factoryInfo);,
+            ons::ONSClientException);
+}
+TEST_F(PropertyTest, testOrderConsumer_SkBeingNone) {
+    ons::ONSFactoryProperty factoryInfo;
+
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::ConsumerId, 
"GID_opensource_unit_test_order");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::AccessKey, "AK");
+    factoryInfo.setFactoryProperty(ons::ONSFactoryProperty::NAMESRV_ADDR,
+                                   
"http://onsaddr.mq-internet-access.mq-internet.aliyuncs.com:80";);
+    EXPECT_THROW(
+            ons::OrderConsumer *consumer_ = 
ons::ONSFactory::getInstance()->createOrderConsumer(factoryInfo);,
+            ons::ONSClientException);
+}
diff --git a/src/test/cpp/TestMain.cpp b/src/test/cpp/TestMain.cpp
new file mode 100644
index 0000000..f81367c
--- /dev/null
+++ b/src/test/cpp/TestMain.cpp
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/src/test/cpp/TransactionTest.cpp b/src/test/cpp/TransactionTest.cpp
new file mode 100644
index 0000000..7ecaac7
--- /dev/null
+++ b/src/test/cpp/TransactionTest.cpp
@@ -0,0 +1,87 @@
+#include <iostream>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "ClientBaseTest.h"
+
+class LocalTransactionCheckerImpl : public ons::LocalTransactionChecker {
+    virtual ons::TransactionStatus check(ons::Message &msg) {
+        cout << "transaction checker::commit transaction" << endl;
+        return ons::CommitTransaction;
+    }
+};
+
+class LocalTransactionExecuterImpl : public ons::LocalTransactionExecuter {
+    virtual ons::TransactionStatus execute(ons::Message &msg) {
+        cout << "transaction executer::commit transaction of msgid: " << 
msg.getMsgID() << endl;
+        return ons::CommitTransaction;
+    }
+};
+
+class TransactionTest : public ClientBaseTest {
+protected:
+    void SetUp() override {
+        ClientBaseTest::SetUp();
+        checker_ = new LocalTransactionCheckerImpl();
+        executor_ = new LocalTransactionExecuterImpl();
+        producer_ = 
ons::ONSFactory::getInstance()->createTransactionProducer(factoryInfo, 
checker_);
+        producer_->start();
+    }
+
+    void TearDown() override {
+        ClientBaseTest::TearDown();
+        producer_->shutdown();
+        delete checker_;
+        delete executor_;
+    }
+
+    ons::TransactionProducer *producer_;
+    LocalTransactionCheckerImpl *checker_;
+    LocalTransactionExecuterImpl *executor_;
+};
+
+TEST_F(TransactionTest, test_setUp) {
+    ASSERT_TRUE(nullptr != producer_);
+}
+
+TEST_F(TransactionTest, testSendMessage_Normal) {
+    ons::Message msg(
+            "lingchu_test_0",
+            "tagA",
+            "ORDERID_100",
+            "hello MQ_lingchu"
+    );
+    ons::SendResultONS sendResult = producer_->send(msg, executor_);
+    ASSERT_TRUE(nullptr != sendResult.getMessageId());
+}
+
+TEST_F(TransactionTest, testSendMessage_ExcutorBeingNull) {
+    ons::Message msg(
+            "lingchu_test_0",
+            "tagA",
+            "ORDERID_100",
+            "hello MQ_lingchu"
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg, NULL), 
ons::ONSClientException);
+}
+
+TEST_F(TransactionTest, testSendMessage_TopicBeingEmpty) {
+    ons::Message msg(
+            "",
+            "tagA",
+            "ORDERID_100",
+            "hello MQ_lingchu"
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg, 
executor_), ons::ONSClientException);
+}
+
+TEST_F(TransactionTest, testSendMessage_TopicNotExist) {
+    ons::Message msg(
+            "topic_not_use_test",
+            "tagA",
+            "ORDERID_100",
+            "hello MQ_lingchu"
+    );
+    EXPECT_THROW(ons::SendResultONS sendResult = producer_->send(msg, 
executor_), ons::ONSClientException);
+}

Reply via email to