diff --git a/CMakeLists.txt b/CMakeLists.txt
index 18a2c2f..cf50b33 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,6 +59,7 @@ add_subdirectory(tinyaes)
 
 if (DEFINED USE_TRANSM_TEST)
 message(STATUS "USE USE_TRANSM_TEST ${USE_TRANSM_TEST}")
+add_definitions(-DUSE_TRANSM_TEST)
 include(CTest)
 add_subdirectory(test)
 endif()
diff --git a/client/client.cpp b/client/client.cpp
index 6f20707..20f5393 100644
--- a/client/client.cpp
+++ b/client/client.cpp
@@ -273,6 +273,7 @@ void TransmClient::run(const std::string& ip, const std::string& port, const std
     TLOGI("{} exit.", __FUNCTION__);
 }
 
+#ifdef USE_TRANSM_TEST
 bool TransmClient::connect_for_test(const std::string& ip, const std::string& port,
                                     const std::string& config_dir)
 {
@@ -284,18 +285,26 @@ bool TransmClient::connect_for_test(const std::string& ip, const std::string& po
     return true;
 }
 
+std::string TransmClient::test_get_own_id() const
+{
+    return own_id_;
+}
+
+void TransmClient::set_task_state(TaskState state)
+{
+    task_state_ = state;
+}
+
+TransmClient::TaskState TransmClient::get_task_state() const
+{
+    return task_state_;
+}
+
 void TransmClient::disconnect_for_test()
 {
     client_->disconnect();
 }
 
-bool TransmClient::get_clients()
-{
-    std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
-    buf->type_ = TYPE_GET_LIST;
-    return send_frame(buf.get());
-}
-
 int TransmClient::test_index_by_id(const std::string& id)
 {
     int ret = -1;
@@ -307,6 +316,14 @@ int TransmClient::test_index_by_id(const std::string& id)
     }
     return ret;
 }
+#endif
+
+bool TransmClient::get_clients()
+{
+    std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
+    buf->type_ = TYPE_GET_LIST;
+    return send_frame(buf.get());
+}
 
 bool TransmClient::cmd_fetch_files(const std::string& param)
 {
@@ -344,12 +361,21 @@ bool TransmClient::cmd_fetch_files(const std::string& param)
     }
 
     // 开始传输文件
+    bool ret = true;
     for (const auto& item : vec) {
         if (!down_one_file(id, item, relative_path)) {
+            ret = false;
             break;
         }
         std::this_thread::sleep_for(std::chrono::milliseconds(20));
     }
+#ifdef USE_TRANSM_TEST
+    if (ret) {
+        task_state_ = TaskState::TASK_STATE_DONE;
+    } else {
+        task_state_ = TaskState::TASK_STATE_ERROR;
+    }
+#endif
     return true;
 }
 
@@ -869,11 +895,6 @@ bool TransmClient::cmd_down_list(const std::string& param)
     return true;
 }
 
-std::string TransmClient::test_get_own_id() const
-{
-    return own_id_;
-}
-
 bool TransmClient::send_frame(CFrameBuffer* buf)
 {
     char* out_buf{};
@@ -1304,10 +1325,16 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
     }
     case TYPE_UNCONFIRM_UPDATE_LIST: {
         TLOGE("remote {} check {} not passed!", buf->fid_, list_file_);
+#ifdef USE_TRANSM_TEST
+        task_state_ = TaskState::TASK_STATE_ERROR;
+#endif
         break;
     }
     case TYPE_DONE_UPDATE_LIST: {
         TLOGI("remote {} do task {} success!", buf->fid_, list_file_);
+#ifdef USE_TRANSM_TEST
+        task_state_ = TaskState::TASK_STATE_DONE;
+#endif
         break;
     }
     case TYPE_FAILED_UPDATE_LIST: {
diff --git a/client/client.h b/client/client.h
index 4cad7d3..5b44373 100644
--- a/client/client.h
+++ b/client/client.h
@@ -55,12 +55,6 @@ public:
     bool cmd_ls(const std::string& param);
     bool cmd_down_list(const std::string& param);
 
-public:
-    bool connect_for_test(const std::string& ip, const std::string& port, const std::string& config_dir);
-    void disconnect_for_test();
-    int test_index_by_id(const std::string& id);
-    std::string test_get_own_id() const;
-
 private:
     bool variable_and_parse_files(const std::string& content, std::map<std::string, std::string>& files);
     bool down_update_file(const std::map<std::string, std::string>& files);
@@ -117,6 +111,27 @@ private:
     std::string config_path_{};
     std::string uuid_path_{};
     std::string uuid_{};
+
+#ifdef USE_TRANSM_TEST
+public:
+    enum TaskState {
+        TASK_STATE_IDLE,
+        TASK_STATE_RUNNING,
+        TASK_STATE_DONE,
+        TASK_STATE_ERROR
+    };
+
+public:
+    bool connect_for_test(const std::string& ip, const std::string& port, const std::string& config_dir);
+    void disconnect_for_test();
+    int test_index_by_id(const std::string& id);
+    std::string test_get_own_id() const;
+    void set_task_state(TaskState state);
+    TaskState get_task_state() const;
+
+private:
+    TaskState task_state_{};
+#endif
 };
 
 class CFileOpr
diff --git a/test/Cmd.cxx b/test/Cmd.cxx
index 6b43491..2a3829f 100644
--- a/test/Cmd.cxx
+++ b/test/Cmd.cxx
@@ -1,5 +1,6 @@
 #include <catch_amalgamated.hpp>
 #include <cstdint>
+#include <fstream>
 
 #include "../client/client.h"
 #include "../client/config.h"
@@ -23,7 +24,14 @@ std::string str_id_a;
 int ida_in_b = -1;
 std::thread server_th;
 
+std::string test_filea = "filea.dat";
+std::string test_fileb = "fileb.dat";
+std::string test_sub_dir = "test_sub";
+std::string test_task_file = "test_task.txt";
+
 bool test_ls();
+bool random_ralated_files();
+bool test_up_task();
 
 void server_run()
 {
@@ -106,6 +114,15 @@ bool main_test()
     if (!test_ls()) {
         return false;
     }
+
+    if (!random_ralated_files()) {
+        return false;
+    }
+
+    if (!test_up_task()) {
+        return false;
+    }
+
     std::this_thread::sleep_for(std::chrono::seconds(10));
     return true;
 }
@@ -120,6 +137,37 @@ bool test_ls()
     return true;
 }
 
+bool test_up_task()
+{
+    std::string cmd = std::to_string(ida_in_b) + " " + test_task_file;
+    if (!clientB->cmd_sub_task(cmd, true)) {
+        return false;
+    }
+    return true;
+}
+
+bool random_ralated_files()
+{
+    if (!random_file("filea.dat", 1024 * 1024 * 10)) {
+        return false;
+    }
+    if (!random_file("fileb.dat", 1024 * 1024 * 10)) {
+        return false;
+    }
+    if (fs::exists(test_sub_dir)) {
+        fs::remove_all(test_sub_dir);
+    }
+    fs::create_directories(test_sub_dir);
+    if (fs::exists(test_task_file)) {
+        fs::remove(test_task_file);
+    }
+    std::ofstream ofs(test_task_file);
+    ofs << "${CURRENT}/" << test_filea << "|" << test_sub_dir + "/" << std::endl;
+    ofs << test_fileb << "|" << test_sub_dir + "/" << std::endl;
+    ofs.close();
+    return true;
+}
+
 TEST_CASE("transm cmd part", "[cmd]")
 {
     SECTION("correctness of cmd")