From ca297d26dc1e7b47d6987c6bbbd92dd2e3d78670 Mon Sep 17 00:00:00 2001
From: jikai <jikai11@huawei.com>
Date: Wed, 22 Nov 2023 22:05:04 +0800
Subject: [PATCH 32/65] add ut for devicemapper

Signed-off-by: jikai <jikai11@huawei.com>
---
 test/image/oci/storage/layers/CMakeLists.txt  |   2 +
 .../storage/layers/devmapper/CMakeLists.txt   |  71 +++++
 ...9702e4bd316dd50ae85467b0378a419b23b60ba73d |   6 +
 ...a9fb83febf6dc0b1548dfe896161533668281c9f4f |   6 +
 ...0a625721fdbea5c94ca6da897acdd814d710149770 |   6 +
 .../devmapper/data/devicemapper/metadata/base |   7 +
 .../devicemapper/metadata/deviceset-metadata  |   5 +
 .../metadata/transaction-metadata             |   5 +
 .../layers/devmapper/driver_devmapper_ut.cc   | 283 ++++++++++++++++++
 test/mocks/libdevmapper_mock.cc               | 191 ++++++++++++
 test/mocks/libdevmapper_mock.h                |  52 ++++
 11 files changed, 634 insertions(+)
 create mode 100644 test/image/oci/storage/layers/devmapper/CMakeLists.txt
 create mode 100644 test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/068615102be4457b22d40c9702e4bd316dd50ae85467b0378a419b23b60ba73d
 create mode 100644 test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f
 create mode 100644 test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770
 create mode 100644 test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/base
 create mode 100644 test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/deviceset-metadata
 create mode 100644 test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/transaction-metadata
 create mode 100644 test/image/oci/storage/layers/devmapper/driver_devmapper_ut.cc
 create mode 100644 test/mocks/libdevmapper_mock.cc
 create mode 100644 test/mocks/libdevmapper_mock.h

diff --git a/test/image/oci/storage/layers/CMakeLists.txt b/test/image/oci/storage/layers/CMakeLists.txt
index 413a8b38..e1c76453 100644
--- a/test/image/oci/storage/layers/CMakeLists.txt
+++ b/test/image/oci/storage/layers/CMakeLists.txt
@@ -1,5 +1,7 @@
 project(iSulad_UT)
 
+add_subdirectory(devmapper)
+
 # storage_driver_ut
 SET(DRIVER_EXE storage_driver_ut)
 
diff --git a/test/image/oci/storage/layers/devmapper/CMakeLists.txt b/test/image/oci/storage/layers/devmapper/CMakeLists.txt
new file mode 100644
index 00000000..f98de1a8
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/CMakeLists.txt
@@ -0,0 +1,71 @@
+project(iSulad_UT)
+
+# driver_devmapper_ut
+SET(DRIVER_DEVMAPPER_EXE driver_devmapper_ut)
+
+add_executable(${DRIVER_DEVMAPPER_EXE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_regex.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_verify.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_array.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_string.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_convert.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_file.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_fs.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/util_atomic.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_base64.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/utils_timestamp.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/path.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/map/map.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/map/rb_tree.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/buffer/buffer.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/tar/util_archive.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/tar/util_gzip.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/sha256/sha256.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/config/daemon_arguments.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/config/isulad_config.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/common/err_msg.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/common/selinux_label.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/metadata_store.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/wrapper_devmapper.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../mocks/libdevmapper_mock.cc
+    driver_devmapper_ut.cc)
+
+target_include_directories(${DRIVER_DEVMAPPER_EXE} PUBLIC
+    ${GTEST_INCLUDE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/common
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/tar
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/cutils/map
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/sha256
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/console
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/utils/buffer
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/config
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/common
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/api
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/remote_layer_support
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/quota
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../mocks
+    )
+
+set_target_properties(${DRIVER_DEVMAPPER_EXE} PROPERTIES LINK_FLAGS "-Wl,--wrap,util_exec_cmd -Wl,--wrap,util_mount -Wl,--wrap,umount2")
+
+target_link_libraries(${DRIVER_DEVMAPPER_EXE}
+    ${GTEST_BOTH_LIBRARIES}
+    ${GMOCK_LIBRARY}
+    ${GMOCK_MAIN_LIBRARY}
+    ${CMAKE_THREAD_LIBS_INIT}
+    ${ISULA_LIBUTILS_LIBRARY}
+    ${LIBTAR_LIBRARY}
+    -lcrypto -lyajl -larchive ${SELINUX_LIBRARY} -lz -lcap)
+
+add_test(NAME ${DRIVER_DEVMAPPER_EXE} COMMAND ${DRIVER_DEVMAPPER_EXE}  --gtest_output=xml:${DRIVER_DEVMAPPER_EXE}-Results.xml)
+set_tests_properties(${DRIVER_DEVMAPPER_EXE} PROPERTIES TIMEOUT 120)
diff --git a/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/068615102be4457b22d40c9702e4bd316dd50ae85467b0378a419b23b60ba73d b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/068615102be4457b22d40c9702e4bd316dd50ae85467b0378a419b23b60ba73d
new file mode 100644
index 00000000..f51ae926
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/068615102be4457b22d40c9702e4bd316dd50ae85467b0378a419b23b60ba73d
@@ -0,0 +1,6 @@
+{
+    "hash": "068615102be4457b22d40c9702e4bd316dd50ae85467b0378a419b23b60ba73d",
+    "device_id": 6,
+    "size": 10737418240,
+    "transaction_id": 8
+}
diff --git a/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f
new file mode 100644
index 00000000..de727a79
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f
@@ -0,0 +1,6 @@
+{
+    "hash": "3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f",
+    "device_id": 4,
+    "size": 10737418240,
+    "transaction_id": 4
+}
diff --git a/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770 b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770
new file mode 100644
index 00000000..e1e8988e
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770
@@ -0,0 +1,6 @@
+{
+    "hash": "ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770",
+    "device_id": 2,
+    "size": 10737418240,
+    "transaction_id": 2
+}
diff --git a/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/base b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/base
new file mode 100644
index 00000000..2412113d
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/base
@@ -0,0 +1,7 @@
+{
+    "hash": "base",
+    "device_id": 1,
+    "size": 10737418240,
+    "transaction_id": 1,
+    "initialized": true
+}
diff --git a/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/deviceset-metadata b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/deviceset-metadata
new file mode 100644
index 00000000..94f7a6a3
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/deviceset-metadata
@@ -0,0 +1,5 @@
+{
+    "next_device_id": 7,
+    "BaseDeviceFilesystem": "ext4",
+    "BaseDeviceUUID": "4fa22307-0c88-4fa4-8f16-a9459e9cbc4a"
+}
diff --git a/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/transaction-metadata b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/transaction-metadata
new file mode 100644
index 00000000..a011249a
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/data/devicemapper/metadata/transaction-metadata
@@ -0,0 +1,5 @@
+{
+    "open_transaction_id": 8,
+    "device_hash": "068615102be4457b22d40c9702e4bd316dd50ae85467b0378a419b23b60ba73d",
+    "device_id": 6
+}
diff --git a/test/image/oci/storage/layers/devmapper/driver_devmapper_ut.cc b/test/image/oci/storage/layers/devmapper/driver_devmapper_ut.cc
new file mode 100644
index 00000000..59e53f97
--- /dev/null
+++ b/test/image/oci/storage/layers/devmapper/driver_devmapper_ut.cc
@@ -0,0 +1,283 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
+ * iSulad licensed under the Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *     http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+ * PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Author: jikai
+ * Create: 2023-11-22
+ * Description: provide oci storage driver unit test for devmapper
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "driver_devmapper.h"
+#include "mock.h"
+#include "path.h"
+#include "utils.h"
+#include "libdevmapper_mock.h"
+
+using ::testing::Invoke;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::_;
+
+extern "C" {
+    DECLARE_WRAPPER_V(util_exec_cmd, bool, (exec_func_t cb_func, void *args, const char *stdin_msg, char **stdout_msg, char **stderr_msg));
+    DEFINE_WRAPPER_V(util_exec_cmd, bool, (exec_func_t cb_func, void *args, const char *stdin_msg, char **stdout_msg, char **stderr_msg), (cb_func, args, stdin_msg, stdout_msg, stderr_msg));
+
+    DECLARE_WRAPPER(util_mount, int, (const char *src, const char *dst, const char *mtype, const char *mntopts));
+    DEFINE_WRAPPER(util_mount, int, (const char *src, const char *dst, const char *mtype, const char *mntopts), (src, dst, mtype, mntopts));
+
+    DECLARE_WRAPPER(umount2, int, (const char *__special_file, int __flags));
+    DEFINE_WRAPPER(umount2, int, (const char *__special_file, int __flags), (__special_file, __flags));
+}
+
+static std::string GetDirectory()
+{
+    char abs_path[PATH_MAX] { 0x00 };
+    int ret = readlink("/proc/self/exe", abs_path, sizeof(abs_path));
+    if (ret < 0 || static_cast<size_t>(ret) >= sizeof(abs_path)) {
+        return "";
+    }
+
+    for (int i { ret }; i >= 0; --i) {
+        if (abs_path[i] == '/') {
+            abs_path[i + 1] = '\0';
+            break;
+        }
+    }
+
+    return static_cast<std::string>(abs_path) + "../../../../../../../test/image/oci/storage/layers/devmapper";
+}
+
+static bool invokeUtilExecCmd(exec_func_t cb_func, void *args, const char *stdin_msg, char **stdout_msg, char **stderr_msg)
+{
+    if (cb_func == nullptr || args == nullptr || stdout_msg == nullptr || stderr_msg == nullptr) {
+        return false;
+    }
+
+    char **tmp_args = static_cast<char **>(args);
+
+    if (util_array_len((const char **)tmp_args) < 1) {
+        return false;
+    }
+
+    if (strcmp(tmp_args[0], "blkid") == 0) {
+        *stdout_msg = util_strdup_s("4fa22307-0c88-4fa4-8f16-a9459e9cbc4a");
+    }
+    return true;
+}
+
+static struct dm_task *invokeDMTaskCreate(int type) {
+    return static_cast<struct dm_task *>(util_common_calloc_s(sizeof(0)));
+}
+
+static void invokeDMTaskDestroy(struct dm_task *task) {
+    free(task);
+    return;
+}
+
+static int invokeDMTaskGetDriverVersion(struct dm_task *task, char *version, size_t size) {
+    if (task == nullptr || version == nullptr || strncpy(version, "4.27.0", size) == NULL) {
+        return 0;
+    }
+
+    return 1;
+}
+
+static int invokeDMTaskGetInfo(struct dm_task *task, struct dm_info *dmi) {
+    if (task == nullptr || dmi == nullptr) {
+        return 0;
+    }
+
+    dmi->exists = 1;
+    return 1;
+}
+
+static void *invokeDMGetNextTarget(struct dm_task *task, void *next, uint64_t *start, uint64_t *length,
+                                   char **target_type, char **params) {
+    static char type[] = "thin-pool";
+    static char par[] = "0 0/1024 0/1024";
+    if (target_type) {
+        *target_type = type;
+    }
+    if (params) {
+        *params = par;
+    }
+    return nullptr;
+}
+
+class DriverDevmapperUnitTest : public testing::Test {
+protected:
+    void SetUp() override
+    {
+        MockLibdevmapper_SetMock(&m_libdevmapper_mock);
+        std::string isulad_dir { "/tmp/isulad/" };
+        mkdir(isulad_dir.c_str(), 0755);
+        std::string root_dir = isulad_dir + "data";
+        std::string run_dir = isulad_dir + "data/run";
+        std::string data_dir = GetDirectory() + "/data";
+        std::string driver_home = root_dir + "/devicemapper";
+
+        ASSERT_STRNE(util_clean_path(data_dir.c_str(), data_path, sizeof(data_path)), nullptr);
+        std::string cp_command = "cp -r " + std::string(data_path) + " " + isulad_dir;
+        ASSERT_EQ(system(cp_command.c_str()), 0);
+
+        char **driver_opts = static_cast<char **>(util_common_calloc_s(3 * sizeof(char *)));
+        driver_opts[0] = strdup("dm.thinpooldev=/dev/mapper/isulad0-thinpool");
+        driver_opts[1] = strdup("dm.fs=ext4");
+        driver_opts[2] = strdup("dm.min_free_space=10%");
+        int driver_opts_len = 3;
+
+        ASSERT_EQ(devmapper_init(&driver, nullptr, (const char **)driver_opts, driver_opts_len), -1);
+
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskCreate(_)).WillRepeatedly(Invoke(invokeDMTaskCreate));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskSetMessage(_, _)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskSetSector(_, _)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskSetAddNode(_, _)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskAddTarget(_, _, _, _, _)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskSetName(_, _)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskRun(_)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskDestroy(_)).WillRepeatedly(Invoke(invokeDMTaskDestroy));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskGetInfo(_, _)).WillRepeatedly(Invoke(invokeDMTaskGetInfo));
+        EXPECT_CALL(m_libdevmapper_mock, DMGetNextTarget(_, _, _, _, _, _)).WillRepeatedly(Invoke(invokeDMGetNextTarget));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskSetCookie(_, _, _)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMUdevWait(_)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMUdevComplete(_)).WillRepeatedly(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskDeferredRemove(_)).WillRepeatedly(Return(1));
+
+
+        char *names = static_cast<char *>(util_common_calloc_s(sizeof(struct dm_names) + strlen("isulad0-pool") + 1));
+        struct dm_names *dname = (struct dm_names *)names;
+        dname->dev = 1;
+        dname->next = 0;
+        strcpy(names + sizeof(struct dm_names), "isulad0-pool");
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskGetNames(_)).WillOnce(Return(dname));
+        EXPECT_CALL(m_libdevmapper_mock, DMSetDevDir(_)).WillOnce(Return(1));
+        EXPECT_CALL(m_libdevmapper_mock, DMTaskGetDriverVersion(_, _, _)).WillOnce(Invoke(invokeDMTaskGetDriverVersion));
+        EXPECT_CALL(m_libdevmapper_mock, DMUdevGetSyncSupport()).WillOnce(Return(1));
+
+        MOCK_SET_V(util_exec_cmd, invokeUtilExecCmd);
+
+        ASSERT_EQ(devmapper_init(&driver, driver_home.c_str(), (const char **)driver_opts, driver_opts_len), 0);
+        MOCK_CLEAR(util_exec_cmd);
+
+        util_free_array_by_len(driver_opts, driver_opts_len);
+        free(names);
+    }
+
+    void TearDown() override
+    {
+        MockLibdevmapper_SetMock(nullptr);
+        std::string rm_command = "rm -rf /tmp/isulad/";
+        ASSERT_EQ(system(rm_command.c_str()), 0);
+    }
+
+    NiceMock<MockLibdevmapper> m_libdevmapper_mock;
+    char data_path[PATH_MAX] = { 0x00 };
+    graphdriver driver = {.ops = nullptr, .name = "devicemapper", };
+};
+
+TEST_F(DriverDevmapperUnitTest, test_devmapper_layer_exists)
+{
+    std::string id { "3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f" };
+    std::string incorrectId { "eb29745b8228e1e97c01b1d5c2554a319c00a94d8dd5746a3904222ad65a13f8" };
+    ASSERT_TRUE(devmapper_layer_exist(id.c_str(), &driver));
+    ASSERT_FALSE(devmapper_layer_exist(incorrectId.c_str(), &driver));
+}
+
+TEST_F(DriverDevmapperUnitTest, test_devmapper_create_rw)
+{
+    std::string id { "eb29745b8228e1e97c01b1d5c2554a319c00a94d8dd5746a3904222ad65a13f8" };
+    struct driver_create_opts *create_opts;
+
+    create_opts = (struct driver_create_opts *)util_common_calloc_s(sizeof(struct driver_create_opts));
+    ASSERT_NE(create_opts, nullptr);
+
+    create_opts->storage_opt = static_cast<json_map_string_string *>(util_common_calloc_s(sizeof(json_map_string_string)));
+    ASSERT_NE(create_opts->storage_opt, nullptr);
+    create_opts->storage_opt->keys = static_cast<char **>(util_common_calloc_s(sizeof(char *)));
+    create_opts->storage_opt->values = static_cast<char **>(util_common_calloc_s(sizeof(char *)));
+    create_opts->storage_opt->keys[0] = strdup("size");
+    create_opts->storage_opt->values[0] = strdup("10G");
+    create_opts->storage_opt->len = 1;
+
+    ASSERT_EQ(devmapper_create_rw(id.c_str(), nullptr, &driver, create_opts), 0);
+    ASSERT_TRUE(devmapper_layer_exist(id.c_str(), &driver));
+}
+
+TEST_F(DriverDevmapperUnitTest, test_devmapper_mount_layer)
+{
+    std::string id { "3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f" };
+    std::string merged_dir = "/tmp/isulad/data/devicemapper/mnt/" + id + "/rootfs";
+    struct driver_mount_opts *mount_opts = nullptr;
+    char* mount_dir = nullptr;
+
+    MOCK_SET(util_mount, 0);
+    mount_dir = devmapper_mount_layer(id.c_str(), &driver, mount_opts);
+    ASSERT_STREQ(mount_dir, merged_dir.c_str());
+    MOCK_CLEAR(util_mount);
+
+    MOCK_SET(umount2, 0);
+    ASSERT_EQ(devmapper_umount_layer(id.c_str(), &driver), 0);
+    MOCK_CLEAR(umount2);
+    free(mount_dir);
+    mount_dir = nullptr;
+
+    mount_opts = static_cast<struct driver_mount_opts *>(util_common_calloc_s(sizeof(struct driver_mount_opts)));
+    ASSERT_NE(mount_opts, nullptr);
+    mount_opts->options = static_cast<char **>(util_common_calloc_s(1 * sizeof(char *)));
+    mount_opts->options[0] = strdup("ro");
+    mount_opts->options_len = 1;
+
+    MOCK_SET(util_mount, 0);
+    mount_dir = devmapper_mount_layer(id.c_str(), &driver, mount_opts);
+    ASSERT_STREQ(mount_dir, merged_dir.c_str());
+    MOCK_CLEAR(util_mount);
+
+    MOCK_SET(umount2, 0);
+    ASSERT_EQ(devmapper_umount_layer(id.c_str(), &driver), 0);
+    MOCK_CLEAR(umount2);
+    free(mount_opts->mount_label);
+    util_free_array_by_len(mount_opts->options, mount_opts->options_len);
+    free(mount_opts);
+    free(mount_dir);
+}
+
+TEST_F(DriverDevmapperUnitTest, test_devmapper_get_layer_metadata)
+{
+    std::string id { "3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f" };
+    json_map_string_string *map_info = static_cast<json_map_string_string *>(util_common_calloc_s(sizeof(json_map_string_string)));
+
+    ASSERT_EQ(devmapper_get_layer_metadata(id.c_str(), &driver, map_info), 0);
+    ASSERT_EQ(map_info->len, 4);
+    ASSERT_STREQ(map_info->keys[0], "DeviceId");
+    ASSERT_STREQ(map_info->values[0], "4");
+    ASSERT_STREQ(map_info->keys[1], "DeviceSize");
+    ASSERT_STREQ(map_info->values[1], "10737418240");
+    ASSERT_STREQ(map_info->keys[2], "DeviceName");
+    ASSERT_STREQ(map_info->keys[3], "MergedDir");
+    ASSERT_STREQ(map_info->values[3], "/tmp/isulad/data/devicemapper/mnt/3d24ee258efc3bfe4066a1a9fb83febf6dc0b1548dfe896161533668281c9f4f/rootfs");
+
+    free_json_map_string_string(map_info);
+}
+
+TEST_F(DriverDevmapperUnitTest, test_devmapper_get_driver_status)
+{
+    struct graphdriver_status *status = static_cast<struct graphdriver_status *>(util_common_calloc_s(sizeof(struct graphdriver_status)));
+
+    EXPECT_CALL(m_libdevmapper_mock, DMUdevGetSyncSupport()).WillOnce(Return(1));
+
+    ASSERT_EQ(devmapper_get_driver_status(&driver, status), 0);
+    ASSERT_STREQ(status->driver_name, "devicemapper");
+    free(status->driver_name);
+    free(status->backing_fs);
+    free(status->status);
+    free(status);
+}
diff --git a/test/mocks/libdevmapper_mock.cc b/test/mocks/libdevmapper_mock.cc
new file mode 100644
index 00000000..7d6c8024
--- /dev/null
+++ b/test/mocks/libdevmapper_mock.cc
@@ -0,0 +1,191 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
+ * iSulad licensed under the Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *     http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+ * PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Author: jikai
+ * Create: 2023-11-22
+ * Description: provide lib device mapper mock
+ ******************************************************************************/
+
+#include "libdevmapper_mock.h"
+
+namespace {
+MockLibdevmapper *g_libdevmapper_mock = nullptr;
+}
+
+void MockLibdevmapper_SetMock(MockLibdevmapper* mock)
+{
+    g_libdevmapper_mock = mock;
+}
+
+struct dm_task *dm_task_create(int type)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskCreate(type);
+    }
+    return nullptr;
+}
+
+int dm_task_set_message(struct dm_task *dmt, const char *msg)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskSetMessage(dmt, msg);
+    }
+    return 0;
+}
+
+int dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskSetSector(dmt, sector);
+    }
+    return 0;
+}
+
+int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskSetAddNode(dmt, add_node);
+    }
+    return 0;
+}
+
+int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size, const char *ttype, const char *params)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskAddTarget(dmt, start, size, ttype, params);
+    }
+    return 0;
+}
+
+int dm_set_dev_dir(const char *dir)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMSetDevDir(dir);
+    }
+    return 0;
+}
+
+int dm_task_set_name(struct dm_task *dmt, const char *name)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskSetName(dmt, name);
+    }
+    return 0;
+}
+
+int dm_task_run(struct dm_task *dmt)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskRun(dmt);
+    }
+    return 0;
+}
+
+int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskGetDriverVersion(dmt, version, size);
+    }
+    return 0;
+}
+
+void dm_task_destroy(struct dm_task *dmt)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        g_libdevmapper_mock->DMTaskDestroy(dmt);
+    }
+}
+
+int dm_get_library_version(char *version, size_t size)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMGetLibraryVersion(version, size);
+    }
+    return 0;
+}
+
+int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskGetInfo(dmt, info);
+    }
+    return 0;
+}
+
+void *dm_get_next_target(struct dm_task *dmt, void *next, uint64_t *start, uint64_t *length,
+                         char **target_type, char **params)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMGetNextTarget(dmt, next, start, length, target_type, params);
+    }
+    return nullptr;
+}
+
+int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskSetCookie(dmt, cookie, flags);
+    }
+    return 0;
+}
+
+int dm_udev_wait(uint32_t cookie)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMUdevWait(cookie);
+    }
+    return 0;
+}
+
+int dm_udev_complete(uint32_t cookie)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMUdevComplete(cookie);
+    }
+    return 0;
+}
+
+int dm_task_deferred_remove(struct dm_task *dmt)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskDeferredRemove(dmt);
+    }
+    return 0;
+}
+
+struct dm_names *dm_task_get_names(struct dm_task *dmt)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMTaskGetNames(dmt);
+    }
+    return nullptr;
+}
+
+int dm_udev_get_sync_support(void)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        return g_libdevmapper_mock->DMUdevGetSyncSupport();
+    }
+    return 0;
+}
+
+void dm_udev_set_sync_support(int sync_with_udev)
+{
+    if (g_libdevmapper_mock != nullptr) {
+        g_libdevmapper_mock->DMUdevSetSyncSupport(sync_with_udev);
+    }
+}
+
+void dm_log_with_errno_init(void log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...))
+{
+    if (g_libdevmapper_mock != nullptr) {
+        g_libdevmapper_mock->DMLogWithErrnoInit(log_cb);
+    }
+}
diff --git a/test/mocks/libdevmapper_mock.h b/test/mocks/libdevmapper_mock.h
new file mode 100644
index 00000000..53c5ad4b
--- /dev/null
+++ b/test/mocks/libdevmapper_mock.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
+ * iSulad licensed under the Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *     http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+ * PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ * Author: jikai
+ * Create: 2023-11-22
+ * Description: provide lib device mapper mock
+ ******************************************************************************/
+
+#ifndef _ISULAD_TEST_MOCKS_DEVMAPPER_MOCK_H
+#define _ISULAD_TEST_MOCKS_DEVMAPPER_MOCK_H
+
+#include <gmock/gmock.h>
+
+#include <libdevmapper.h>
+
+class MockLibdevmapper {
+public:
+    virtual ~MockLibdevmapper() = default;
+    MOCK_METHOD1(DMTaskCreate, struct dm_task*(int type));
+    MOCK_METHOD2(DMTaskSetMessage, int(struct dm_task *dmt, const char *msg));
+    MOCK_METHOD2(DMTaskSetSector, int(struct dm_task *dmt, uint64_t sector));
+    MOCK_METHOD2(DMTaskSetAddNode, int(struct dm_task *dmt, dm_add_node_t add_node));
+    MOCK_METHOD5(DMTaskAddTarget, int(struct dm_task *dmt, uint64_t start, uint64_t size, const char *ttype, const char *params));
+    MOCK_METHOD1(DMSetDevDir, int(const char *dir));
+    MOCK_METHOD2(DMTaskSetName, int(struct dm_task *dmt, const char *name));
+    MOCK_METHOD1(DMTaskRun, int(struct dm_task *dmt));
+    MOCK_METHOD3(DMTaskGetDriverVersion, int(struct dm_task *dmt, char *version, size_t size));
+    MOCK_METHOD1(DMTaskDestroy, void(struct dm_task *dmt));
+    MOCK_METHOD2(DMGetLibraryVersion, int(char *version, size_t size));
+    MOCK_METHOD2(DMTaskGetInfo, int(struct dm_task *dmt, struct dm_info *info));
+    MOCK_METHOD6(DMGetNextTarget, void*(struct dm_task *dmt, void *next, uint64_t *start, uint64_t *length,
+			                            char **target_type, char **params));
+    MOCK_METHOD3(DMTaskSetCookie, int(struct dm_task *dmt, uint32_t *cookie, uint16_t flags));
+    MOCK_METHOD1(DMUdevWait, int(uint32_t cookie));
+    MOCK_METHOD1(DMUdevComplete, int(uint32_t cookie));
+    MOCK_METHOD1(DMTaskDeferredRemove, int(struct dm_task *dmt));
+    MOCK_METHOD1(DMTaskGetNames, struct dm_names *(struct dm_task *dmt));
+    MOCK_METHOD0(DMUdevGetSyncSupport, int(void));
+    MOCK_METHOD1(DMUdevSetSyncSupport, void(int sync_with_udev));
+    MOCK_METHOD1(DMLogWithErrnoInit, void(void log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...)));
+};
+
+void MockLibdevmapper_SetMock(MockLibdevmapper* mock);
+
+#endif
-- 
2.42.0

