summaryrefslogtreecommitdiff
path: root/0076-cdi-add-UT.patch
diff options
context:
space:
mode:
Diffstat (limited to '0076-cdi-add-UT.patch')
-rw-r--r--0076-cdi-add-UT.patch741
1 files changed, 741 insertions, 0 deletions
diff --git a/0076-cdi-add-UT.patch b/0076-cdi-add-UT.patch
new file mode 100644
index 0000000..678b578
--- /dev/null
+++ b/0076-cdi-add-UT.patch
@@ -0,0 +1,741 @@
+From 0cd088174c94c56ee86506dab9a6a33f6e8fdaa4 Mon Sep 17 00:00:00 2001
+From: liuxu <liuxu156@huawei.com>
+Date: Thu, 25 Apr 2024 10:52:20 +0800
+Subject: [PATCH 76/78] cdi:add UT
+
+Signed-off-by: liuxu <liuxu156@huawei.com>
+---
+ CI/make-and-install.sh | 4 +-
+ test/cutils/CMakeLists.txt | 1 +
+ test/cutils/utils_array/utils_array_ut.cc | 128 ++++++++++
+ test/cutils/utils_utils/utils_utils_ut.cc | 12 +
+ test/cutils/utils_version/CMakeLists.txt | 17 ++
+ test/cutils/utils_version/utils_version_ut.cc | 71 ++++++
+ .../image/oci/oci_config_merge/CMakeLists.txt | 1 +
+ test/mocks/cdi_operate_api_mock.cc | 58 +++++
+ test/mocks/cdi_operate_api_mock.h | 35 +++
+ test/sandbox/controller/shim/CMakeLists.txt | 1 +
+ test/specs/specs/CMakeLists.txt | 1 +
+ test/specs/specs/specs_ut.cc | 241 ++++++++++++++++++
+ test/specs/specs_extend/CMakeLists.txt | 1 +
+ 13 files changed, 569 insertions(+), 2 deletions(-)
+ create mode 100644 test/cutils/utils_version/CMakeLists.txt
+ create mode 100644 test/cutils/utils_version/utils_version_ut.cc
+ create mode 100644 test/mocks/cdi_operate_api_mock.cc
+ create mode 100644 test/mocks/cdi_operate_api_mock.h
+
+diff --git a/CI/make-and-install.sh b/CI/make-and-install.sh
+index 9bb984cd..9d4c5533 100755
+--- a/CI/make-and-install.sh
++++ b/CI/make-and-install.sh
+@@ -72,7 +72,7 @@ cd $ISULAD_COPY_PATH
+ sed -i 's/fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO/fd == 0 || fd == 1 || fd == 2 || fd >= 1000/g' ./src/utils/cutils/utils.c
+ rm -rf build
+ mkdir build && cd build
+-cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_UT=ON -DENABLE_CRI_API_V1=ON -DENABLE_SHIM_V2=ON -DENABLE_METRICS=ON ..
++cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_UT=ON -DENABLE_CRI_API_V1=ON -DENABLE_CDI=ON -DENABLE_SHIM_V2=ON -DENABLE_METRICS=ON ..
+ make -j $(nproc)
+ make install
+ ctest -E "driver_devmapper_ut" -T memcheck --output-on-failure
+@@ -103,7 +103,7 @@ rm -rf build
+ mkdir build
+ cd build
+ if [[ ${enable_gcov} -ne 0 ]]; then
+- cmake -DLIB_INSTALL_DIR=${builddir}/lib -DCMAKE_INSTALL_PREFIX=${builddir} -DCMAKE_INSTALL_SYSCONFDIR=${builddir}/etc -DCMAKE_BUILD_TYPE=Debug -DGCOV=ON -DENABLE_EMBEDDED=ON -DENABLE_COVERAGE=ON -DENABLE_CRI_API_V1=ON -DENABLE_UT=ON -DENABLE_METRICS=ON -DENABLE_REMOTE_LAYER_STORE=ON -DENABLE_GRPC_REMOTE_CONNECT=ON ..
++ cmake -DLIB_INSTALL_DIR=${builddir}/lib -DCMAKE_INSTALL_PREFIX=${builddir} -DCMAKE_INSTALL_SYSCONFDIR=${builddir}/etc -DCMAKE_BUILD_TYPE=Debug -DGCOV=ON -DENABLE_EMBEDDED=ON -DENABLE_COVERAGE=ON -DENABLE_CRI_API_V1=ON -DENABLE_CDI=ON -DENABLE_UT=ON -DENABLE_METRICS=ON -DENABLE_REMOTE_LAYER_STORE=ON -DENABLE_GRPC_REMOTE_CONNECT=ON ..
+ else
+ cmake -DLIB_INSTALL_DIR=${builddir}/lib -DCMAKE_INSTALL_PREFIX=${builddir} -DCMAKE_INSTALL_SYSCONFDIR=${builddir}/etc -DENABLE_EMBEDDED=ON -DENABLE_METRICS=ON -DENABLE_REMOTE_LAYER_STORE=ON -DENABLE_CRI_API_V1=ON -DENABLE_GRPC_REMOTE_CONNECT=ON ..
+ fi
+diff --git a/test/cutils/CMakeLists.txt b/test/cutils/CMakeLists.txt
+index 9e681cc9..bd9def02 100644
+--- a/test/cutils/CMakeLists.txt
++++ b/test/cutils/CMakeLists.txt
+@@ -34,4 +34,5 @@ add_subdirectory(utils_utils)
+ add_subdirectory(utils_verify)
+ add_subdirectory(utils_network)
+ add_subdirectory(utils_transform)
++add_subdirectory(utils_version)
+ add_subdirectory(map)
+diff --git a/test/cutils/utils_array/utils_array_ut.cc b/test/cutils/utils_array/utils_array_ut.cc
+index 7bd13c25..6c6e76fa 100644
+--- a/test/cutils/utils_array/utils_array_ut.cc
++++ b/test/cutils/utils_array/utils_array_ut.cc
+@@ -50,6 +50,33 @@ TEST(utils_array, test_util_free_array)
+ util_free_array(array);
+ }
+
++TEST(utils_array, test_util_copy_array_by_len)
++{
++ char **array = nullptr;
++ char **array_copy = nullptr;
++ size_t len = 3;
++
++ array = (char **)util_common_calloc_s(4 * sizeof(char *));
++ ASSERT_NE(array, nullptr);
++ array[0] = util_strdup_s("test1");
++ array[1] = util_strdup_s("test2");
++ array[2] = util_strdup_s("test3");
++
++ array_copy = util_copy_array_by_len(array, len);
++ ASSERT_NE(array_copy, nullptr);
++ for (size_t i = 0; i < len; i++) {
++ ASSERT_EQ(strcmp(array_copy[i], array[i]), 0);
++ free(array[i]);
++ free(array_copy[i]);
++ }
++
++ ASSERT_EQ(util_copy_array_by_len(array, 0), nullptr);
++ ASSERT_EQ(util_copy_array_by_len(nullptr, len), nullptr);
++
++ free(array);
++ free(array_copy);
++}
++
+ TEST(utils_array, test_util_grow_array)
+ {
+ char **array = nullptr;
+@@ -229,6 +256,34 @@ TEST(utils_array, test_util_append_string_array)
+ sarray = nullptr;
+ }
+
++TEST(utils_array, test_util_copy_string_array)
++{
++ __isula_auto_string_array_t string_array *sarray_copy = nullptr;
++ __isula_auto_string_array_t string_array *sarray = (string_array *)util_common_calloc_s(sizeof(string_array));
++ ASSERT_NE(sarray, nullptr);
++ int ret;
++
++ ret = util_append_string_array(sarray, "1234567890");
++ ASSERT_EQ(ret, 0);
++ ret = util_append_string_array(sarray, "abc");
++ ASSERT_EQ(ret, 0);
++ ret = util_append_string_array(sarray, "bcd");
++ ASSERT_EQ(ret, 0);
++ ASSERT_EQ(sarray->len, 3);
++
++ sarray_copy = util_copy_string_array(sarray);
++ ASSERT_NE(sarray_copy, nullptr);
++ ASSERT_EQ(sarray_copy->len, sarray->len);
++ for (size_t i = 0; i < sarray_copy->len; i++) {
++ ASSERT_EQ(strcmp(sarray_copy->items[i], sarray->items[i]), 0);
++ }
++
++ ASSERT_EQ(util_copy_string_array(nullptr), nullptr);
++ sarray->cap = 0;
++ ASSERT_EQ(util_copy_string_array(sarray), nullptr);
++ sarray->cap = sarray->len;
++}
++
+ TEST(utils_array, test_util_string_array_contain)
+ {
+ string_array *sarray = (string_array *)util_common_calloc_s(sizeof(string_array));
+@@ -299,3 +354,76 @@ TEST(utils_array, test_util_common_array_append_pointer)
+ delete element1;
+ delete element2;
+ }
++
++static void common_array_free_mock(void *ptr)
++{
++ (void)ptr;
++ return;
++}
++
++TEST(utils_array, test_util_append_common_array)
++{
++ __isula_auto_common_array_t common_array *carray = nullptr;
++ int ret;
++ int value1 = 1;
++ int value2 = 2;
++ int value3 = 3;
++
++ carray = util_common_array_new(1, common_array_free_mock, util_clone_ptr);
++ ASSERT_NE(carray, nullptr);
++
++ ret = util_append_common_array(carray, &value1);
++ ASSERT_EQ(ret, 0);
++ ASSERT_EQ(carray->items[0], &value1);
++ ASSERT_EQ(carray->len, 1);
++
++ ret = util_append_common_array(carray, &value2);
++ ASSERT_EQ(ret, 0);
++ ret = util_append_common_array(carray, &value3);
++ ASSERT_EQ(ret, 0);
++ ASSERT_EQ(carray->items[1], &value2);
++ ASSERT_EQ(carray->items[2], &value3);
++ ASSERT_EQ(carray->len, 3);
++
++ carray->clone_item_cb = nullptr;
++ ASSERT_EQ(util_append_common_array(carray, &value1), -1);
++ carray->clone_item_cb = util_clone_ptr;
++ ASSERT_EQ(util_append_common_array(carray, nullptr), 0);
++}
++
++TEST(utils_array, test_util_merge_common_array)
++{
++ __isula_auto_common_array_t common_array *carray1 = nullptr;
++ __isula_auto_common_array_t common_array *carray2 = nullptr;
++ int ret;
++ int value1 = 1;
++ int value2 = 2;
++
++ carray1 = util_common_array_new(1, common_array_free_mock, util_clone_ptr);
++ ASSERT_NE(carray1, nullptr);
++ carray2 = util_common_array_new(1, common_array_free_mock, util_clone_ptr);
++ ASSERT_NE(carray2, nullptr);
++
++ ret = util_append_common_array(carray1, &value1);
++ ASSERT_EQ(ret, 0);
++ ASSERT_EQ(carray1->items[0], &value1);
++ ASSERT_EQ(carray1->len, 1);
++ ret = util_append_common_array(carray2, &value2);
++ ASSERT_EQ(ret, 0);
++ ASSERT_EQ(carray2->items[0], &value2);
++ ASSERT_EQ(carray2->len, 1);
++
++ ret = util_merge_common_array(carray1, carray2);
++ ASSERT_EQ(ret, 0);
++ ASSERT_EQ(carray1->items[1], &value2);
++ ASSERT_EQ(carray1->len, 2);
++
++ ASSERT_EQ(util_merge_common_array(nullptr, carray2), -1);
++ ASSERT_EQ(util_merge_common_array(carray1, nullptr), -1);
++ carray1->clone_item_cb = nullptr;
++ ASSERT_EQ(util_merge_common_array(carray1, carray2), -1);
++ carray1->clone_item_cb = util_clone_ptr;
++ carray2->clone_item_cb = nullptr;
++ ASSERT_EQ(util_merge_common_array(carray1, carray2), -1);
++ carray2->clone_item_cb = util_clone_ptr;
++}
+\ No newline at end of file
+diff --git a/test/cutils/utils_utils/utils_utils_ut.cc b/test/cutils/utils_utils/utils_utils_ut.cc
+index 0720d1b1..a61e5a21 100644
+--- a/test/cutils/utils_utils/utils_utils_ut.cc
++++ b/test/cutils/utils_utils/utils_utils_ut.cc
+@@ -54,6 +54,18 @@ static int status_to_exit_code(int status)
+ return exit_code;
+ }
+
++TEST(utils_utils, test_util_swap_ptr)
++{
++ int val1 = 1;
++ int val2 = 2;
++ int *ptr1 = &val1;
++ int *ptr2 = &val2;
++
++ util_swap_ptr((void **)&ptr1, (void **)&ptr2);
++ ASSERT_EQ(*ptr1, val2);
++ ASSERT_EQ(*ptr2, val1);
++}
++
+ TEST(utils_utils, test_util_mem_realloc)
+ {
+ char *old = nullptr;
+diff --git a/test/cutils/utils_version/CMakeLists.txt b/test/cutils/utils_version/CMakeLists.txt
+new file mode 100644
+index 00000000..1ada8e93
+--- /dev/null
++++ b/test/cutils/utils_version/CMakeLists.txt
+@@ -0,0 +1,17 @@
++project(iSulad_UT)
++
++SET(EXE utils_version_ut)
++
++add_executable(${EXE}
++ utils_version_ut.cc)
++
++target_include_directories(${EXE} PUBLIC
++ ${GTEST_INCLUDE_DIR}
++ ${CMAKE_CURRENT_SOURCE_DIR}/../../include
++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/common
++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils
++ )
++
++target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} libutils_ut -lcrypto -lyajl -lz)
++add_test(NAME ${EXE} COMMAND ${EXE} --gtest_output=xml:${EXE}-Results.xml)
++set_tests_properties(${EXE} PROPERTIES TIMEOUT 120)
+diff --git a/test/cutils/utils_version/utils_version_ut.cc b/test/cutils/utils_version/utils_version_ut.cc
+new file mode 100644
+index 00000000..d1fc0932
+--- /dev/null
++++ b/test/cutils/utils_version/utils_version_ut.cc
+@@ -0,0 +1,71 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. 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: liuxu
++ * Create: 2024-04-25
++ * Description: utils version unit test
++ *******************************************************************************/
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <climits>
++#include <gtest/gtest.h>
++#include "mock.h"
++#include "utils_version.h"
++#include "utils.h"
++
++TEST(utils_version, test_util_version_compare)
++{
++ const char *version1 = "1.1.1";
++ const char *version2 = "1.1.2";
++ int diff_value = 0;
++
++ ASSERT_EQ(util_version_compare(version1, version2, &diff_value), 0);
++ ASSERT_TRUE(diff_value < 0);
++ ASSERT_EQ(util_version_compare(version1, version1, &diff_value), 0);
++ ASSERT_TRUE(diff_value == 0);
++ ASSERT_EQ(util_version_compare(version2, version1, &diff_value), 0);
++ ASSERT_TRUE(diff_value > 0);
++
++ ASSERT_EQ(util_version_compare(version1, nullptr, &diff_value), -1);
++ ASSERT_EQ(util_version_compare(nullptr, version2, &diff_value), -1);
++ ASSERT_EQ(util_version_compare(version1, version2, nullptr), -1);
++ ASSERT_EQ(util_version_compare("1.1.1.1", version2, nullptr), -1);
++ ASSERT_EQ(util_version_compare(version1, "a.b.1.1", nullptr), -1);
++}
++
++TEST(utils_version, test_util_version_greater_than)
++{
++ const char *version1 = "0.6.0";
++ const char *version2 = "1.0.0";
++ bool result = true;
++
++ ASSERT_EQ(util_version_greater_than(version1, version2, &result), 0);
++ ASSERT_FALSE(result);
++ ASSERT_EQ(util_version_greater_than(version1, version1, &result), 0);
++ ASSERT_FALSE(result);
++ ASSERT_EQ(util_version_greater_than(version2, version1, &result), 0);
++ ASSERT_TRUE(result);
++}
++
++TEST(utils_version, test_util_version_greater_than_or_equal_to)
++{
++ const char *version1 = "0.6.0";
++ const char *version2 = "1.0.0";
++ bool result = true;
++
++ ASSERT_EQ(util_version_greater_than_or_equal_to(version1, version2, &result), 0);
++ ASSERT_FALSE(result);
++ ASSERT_EQ(util_version_greater_than_or_equal_to(version1, version1, &result), 0);
++ ASSERT_TRUE(result);
++ ASSERT_EQ(util_version_greater_than_or_equal_to(version2, version1, &result), 0);
++ ASSERT_TRUE(result);
++}
++
+diff --git a/test/image/oci/oci_config_merge/CMakeLists.txt b/test/image/oci/oci_config_merge/CMakeLists.txt
+index ffd3999d..38ade4ec 100644
+--- a/test/image/oci/oci_config_merge/CMakeLists.txt
++++ b/test/image/oci/oci_config_merge/CMakeLists.txt
+@@ -47,6 +47,7 @@ add_executable(${EXE}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/selinux_label_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/storage_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/image_mock.cc
++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/cdi_operate_api_mock.cc
+ oci_config_merge_ut.cc)
+
+ target_include_directories(${EXE} PUBLIC
+diff --git a/test/mocks/cdi_operate_api_mock.cc b/test/mocks/cdi_operate_api_mock.cc
+new file mode 100644
+index 00000000..d8f9f9d4
+--- /dev/null
++++ b/test/mocks/cdi_operate_api_mock.cc
+@@ -0,0 +1,58 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2023. 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-10-20
++ * Description: provide image api mock
++ ******************************************************************************/
++
++#include "cdi_operate_api_mock.h"
++
++namespace {
++std::shared_ptr<MockCdiOperateApi> g_cdi_operate_api_mock = nullptr;
++}
++
++void MockCdiOperateApi_SetMock(std::shared_ptr<MockCdiOperateApi> mock)
++{
++ g_cdi_operate_api_mock = mock;
++}
++
++int cdi_operate_registry_init(char **specs_dirs, size_t specs_dirs_len)
++{
++ if (g_cdi_operate_api_mock != nullptr) {
++ return g_cdi_operate_api_mock->CdiOperateRegistryInit(specs_dirs, specs_dirs_len);
++ }
++ return 0;
++}
++
++int cdi_operate_refresh(void)
++{
++ if (g_cdi_operate_api_mock != nullptr) {
++ return g_cdi_operate_api_mock->CdiOperateRefresh();
++ }
++ return 0;
++}
++
++int cdi_operate_inject_devices(oci_runtime_spec *spec, string_array *devices)
++{
++ if (g_cdi_operate_api_mock != nullptr) {
++ return g_cdi_operate_api_mock->CdiOperateInjectDevices(spec, devices);
++ }
++ return 0;
++}
++
++int cdi_operate_parse_annotations(json_map_string_string *annotations, string_array **keys,
++ string_array **devices, char **error)
++{
++ if (g_cdi_operate_api_mock != nullptr) {
++ return g_cdi_operate_api_mock->CdiOperateParseAnnotations(annotations, keys, devices, error);
++ }
++ return 0;
++}
+\ No newline at end of file
+diff --git a/test/mocks/cdi_operate_api_mock.h b/test/mocks/cdi_operate_api_mock.h
+new file mode 100644
+index 00000000..c118ee7a
+--- /dev/null
++++ b/test/mocks/cdi_operate_api_mock.h
+@@ -0,0 +1,35 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2023. 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: liuxu
++ * Create: 2024-04-24
++ * Description: provide cdi api mock
++ ******************************************************************************/
++
++#ifndef ISULAD_TEST_MOCKS_CDI_OPERATE_API_MOCK_H
++#define ISULAD_TEST_MOCKS_CDI_OPERATE_API_MOCK_H
++
++#include <gmock/gmock.h>
++#include <memory>
++
++#include "cdi_operate_api.h"
++
++class MockCdiOperateApi {
++public:
++ MOCK_METHOD2(CdiOperateRegistryInit, int(char **specs_dirs, size_t specs_dirs_len));
++ MOCK_METHOD0(CdiOperateRefresh, int(void));
++ MOCK_METHOD2(CdiOperateInjectDevices, int(oci_runtime_spec *spec, string_array *devices));
++ MOCK_METHOD4(CdiOperateParseAnnotations, int(json_map_string_string *annotations, string_array **keys,
++ string_array **devices, char **error));
++};
++
++void MockCdiOperateApi_SetMock(std::shared_ptr<MockCdiOperateApi> mock);
++
++#endif
+diff --git a/test/sandbox/controller/shim/CMakeLists.txt b/test/sandbox/controller/shim/CMakeLists.txt
+index 26a66e51..d18d1861 100644
+--- a/test/sandbox/controller/shim/CMakeLists.txt
++++ b/test/sandbox/controller/shim/CMakeLists.txt
+@@ -21,6 +21,7 @@ add_executable(${EXE}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/callback_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/image_api_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/service_container_api_mock.cc
++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/cdi_operate_api_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/sandbox/controller/controller_common.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/sandbox/controller/shim/shim_controller_ut.cc
+ )
+diff --git a/test/specs/specs/CMakeLists.txt b/test/specs/specs/CMakeLists.txt
+index 12c11f51..892d44d7 100644
+--- a/test/specs/specs/CMakeLists.txt
++++ b/test/specs/specs/CMakeLists.txt
+@@ -44,6 +44,7 @@ add_executable(${EXE}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/storage_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/image_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/sender_mock.cc
++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/cdi_operate_api_mock.cc
+ specs_ut.cc)
+
+ target_include_directories(${EXE} PUBLIC
+diff --git a/test/specs/specs/specs_ut.cc b/test/specs/specs/specs_ut.cc
+index 6c42216d..47836e5b 100644
+--- a/test/specs/specs/specs_ut.cc
++++ b/test/specs/specs/specs_ut.cc
+@@ -564,6 +564,247 @@ TEST_F(SpecsUnitTest, test_update_devcies_for_oci_spec)
+ free(err);
+ }
+
++#ifdef ENABLE_CDI
++TEST_F(SpecsUnitTest, test_defs_process_add_multiple_env)
++{
++ size_t env_len = 2;
++ char **envs = (char **)util_common_calloc_s(sizeof(char *) * env_len);
++ ASSERT_NE(envs, nullptr);
++ defs_process *dp = (defs_process *)util_common_calloc_s(sizeof(defs_process));
++ ASSERT_NE(dp, nullptr);
++ dp->env_len = 1;
++ dp->env = (char **)util_common_calloc_s(sizeof(char *) * dp->env_len);
++ ASSERT_NE(dp->env, nullptr);
++
++ envs[0] = util_strdup_s("key0=value0");
++ envs[1] = util_strdup_s("key1=value1");
++ dp->env[0] = util_strdup_s("key0=value0_old");
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, env_len), 0);
++ ASSERT_EQ(dp->env_len, 2);
++ ASSERT_EQ(strcmp(dp->env[0], envs[0]), 0);
++ ASSERT_EQ(strcmp(dp->env[1], envs[1]), 0);
++
++ ASSERT_EQ(defs_process_add_multiple_env(dp, nullptr, env_len), 0);
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, 0), 0);
++ ASSERT_EQ(defs_process_add_multiple_env(nullptr, (const char **)envs, env_len), -1);
++
++ free(envs[0]);
++ envs[0] = util_strdup_s("=value0");
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, env_len), -1);
++ free(envs[0]);
++ envs[0] = util_strdup_s("key0=");
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, env_len), -1);
++ free(envs[0]);
++ envs[0] = util_strdup_s("key0xxxx");
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, env_len), -1);
++
++ free(dp->env[0]);
++ dp->env[0] = util_strdup_s("=value0");
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, env_len), -1);
++ free(dp->env[0]);
++ dp->env[0] = util_strdup_s("key0=");
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, env_len), -1);
++ free(dp->env[0]);
++ dp->env[0] = util_strdup_s("key0xxxx");
++ ASSERT_EQ(defs_process_add_multiple_env(dp, (const char **)envs, env_len), -1);
++
++ free_defs_process(dp);
++ free(envs[0]);
++ free(envs[1]);
++ free(envs);
++}
++
++TEST_F(SpecsUnitTest, test_spec_add_multiple_process_env)
++{
++ size_t env_len = 2;
++ char **envs = (char **)util_common_calloc_s(sizeof(char *) * env_len);
++ ASSERT_NE(envs, nullptr);
++ oci_runtime_spec *oci_spec = (oci_runtime_spec *)util_common_calloc_s(sizeof(oci_runtime_spec));
++ ASSERT_NE(oci_spec, nullptr);
++ oci_spec->process = (defs_process *)util_common_calloc_s(sizeof(defs_process));
++ ASSERT_NE(oci_spec->process, nullptr);
++ oci_spec->process->env_len = 1;
++ oci_spec->process->env = (char **)util_common_calloc_s(sizeof(char *) * oci_spec->process->env_len);
++ ASSERT_NE(oci_spec->process->env, nullptr);
++
++ envs[0] = util_strdup_s("key0=value0");
++ envs[1] = util_strdup_s("key1=value1");
++ oci_spec->process->env[0] = util_strdup_s("key0=value0_old");
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, env_len), 0);
++ ASSERT_EQ(oci_spec->process->env_len, 2);
++ ASSERT_EQ(strcmp(oci_spec->process->env[0], envs[0]), 0);
++ ASSERT_EQ(strcmp(oci_spec->process->env[1], envs[1]), 0);
++
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, nullptr, env_len), 0);
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, 0), 0);
++ ASSERT_EQ(spec_add_multiple_process_env(nullptr, (const char **)envs, env_len), -1);
++
++ free(envs[0]);
++ envs[0] = util_strdup_s("=value0");
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, env_len), -1);
++ free(envs[0]);
++ envs[0] = util_strdup_s("key0=");
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, env_len), -1);
++ free(envs[0]);
++ envs[0] = util_strdup_s("key0xxxx");
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, env_len), -1);
++
++ free(oci_spec->process->env[0]);
++ oci_spec->process->env[0] = util_strdup_s("=value0");
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, env_len), -1);
++ free(oci_spec->process->env[0]);
++ oci_spec->process->env[0] = util_strdup_s("key0=");
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, env_len), -1);
++ free(oci_spec->process->env[0]);
++ oci_spec->process->env[0] = util_strdup_s("key0xxxx");
++ ASSERT_EQ(spec_add_multiple_process_env(oci_spec, (const char **)envs, env_len), -1);
++
++ free_oci_runtime_spec(oci_spec);
++ free(envs[0]);
++ free(envs[1]);
++ free(envs);
++}
++
++TEST_F(SpecsUnitTest, test_spec_add_device)
++{
++ defs_device *device = (defs_device *)util_common_calloc_s(sizeof(defs_device));
++ ASSERT_NE(device, nullptr);
++ oci_runtime_spec *oci_spec = (oci_runtime_spec *)util_common_calloc_s(sizeof(oci_runtime_spec));
++ ASSERT_NE(oci_spec, nullptr);
++ oci_spec->linux = (oci_runtime_config_linux *)util_common_calloc_s(sizeof(oci_runtime_config_linux));
++ ASSERT_NE(oci_spec->linux, nullptr);
++ oci_spec->linux->devices_len = 1;
++ oci_spec->linux->devices = (defs_device **)util_common_calloc_s(sizeof(defs_device *) * oci_spec->linux->devices_len);
++ ASSERT_NE(oci_spec->linux->devices, nullptr);
++
++ device->path = util_strdup_s("/device/path");
++ oci_spec->linux->devices[0] = (defs_device *)util_common_calloc_s(sizeof(defs_device));
++ ASSERT_NE(oci_spec->linux->devices[0], nullptr);
++ oci_spec->linux->devices[0]->path = util_strdup_s("/device/path");
++ ASSERT_EQ(spec_add_device(oci_spec, device), 0);
++ ASSERT_EQ(oci_spec->linux->devices[0], device);
++
++ oci_spec->linux->devices[0] = nullptr;
++ oci_spec->linux->devices_len = 0;
++ ASSERT_EQ(spec_add_device(oci_spec, device), 0);
++ ASSERT_EQ(oci_spec->linux->devices_len, 1);
++ ASSERT_EQ(oci_spec->linux->devices[0], device);
++
++ ASSERT_EQ(spec_add_device(oci_spec, nullptr), -1);
++ ASSERT_EQ(spec_add_device(nullptr, device), -1);
++
++ free_oci_runtime_spec(oci_spec);
++}
++
++TEST_F(SpecsUnitTest, test_spec_add_linux_resources_device)
++{
++ oci_runtime_spec *oci_spec = (oci_runtime_spec *)util_common_calloc_s(sizeof(oci_runtime_spec));
++ ASSERT_NE(oci_spec, nullptr);
++ oci_spec->linux = (oci_runtime_config_linux *)util_common_calloc_s(sizeof(oci_runtime_config_linux));
++ ASSERT_NE(oci_spec->linux, nullptr);
++ oci_spec->linux->resources = (defs_resources *)util_common_calloc_s(sizeof(defs_resources));
++ ASSERT_NE(oci_spec->linux->resources, nullptr);
++ oci_spec->linux->resources->devices_len = 1;
++ oci_spec->linux->resources->devices = (defs_device_cgroup **)util_common_calloc_s(sizeof(defs_device_cgroup *) * oci_spec->linux->resources->devices_len);
++ ASSERT_NE(oci_spec->linux->resources->devices, nullptr);
++
++ oci_spec->linux->resources->devices[0] = (defs_device_cgroup *)util_common_calloc_s(sizeof(defs_device_cgroup));
++ ASSERT_NE(oci_spec->linux->resources->devices[0], nullptr);
++ ASSERT_EQ(spec_add_linux_resources_device(oci_spec, true, "bind", 10, 9, "rwm"), 0);
++ ASSERT_EQ(oci_spec->linux->resources->devices_len, 2);
++ ASSERT_EQ(oci_spec->linux->resources->devices[1]->allow, true);
++ ASSERT_EQ(strcmp(oci_spec->linux->resources->devices[1]->type, "bind"), 0);
++ ASSERT_EQ(oci_spec->linux->resources->devices[1]->major, 10);
++ ASSERT_EQ(oci_spec->linux->resources->devices[1]->minor, 9);
++ ASSERT_EQ(strcmp(oci_spec->linux->resources->devices[1]->access, "rwm"), 0);
++
++ ASSERT_EQ(spec_add_linux_resources_device(nullptr, true, "bind", 10, 9, "rwm"), -1);
++
++ free_oci_runtime_spec(oci_spec);
++}
++
++TEST_F(SpecsUnitTest, test_spec_remove_mount)
++{
++ oci_runtime_spec *oci_spec = (oci_runtime_spec *)util_common_calloc_s(sizeof(oci_runtime_spec));
++ ASSERT_NE(oci_spec, nullptr);
++ oci_spec->mounts_len = 2;
++ oci_spec->mounts = (defs_mount **)util_common_calloc_s(sizeof(defs_mount *) * oci_spec->mounts_len);
++ ASSERT_NE(oci_spec->mounts, nullptr);
++
++ oci_spec->mounts[0] = (defs_mount *)util_common_calloc_s(sizeof(defs_mount));
++ ASSERT_NE(oci_spec->mounts[0], nullptr);
++ oci_spec->mounts[1] = (defs_mount *)util_common_calloc_s(sizeof(defs_mount));
++ ASSERT_NE(oci_spec->mounts[1], nullptr);
++ oci_spec->mounts[0]->destination = util_strdup_s("/mount/path/0");
++ oci_spec->mounts[1]->destination = util_strdup_s("/mount/path/1");
++ spec_remove_mount(oci_spec, oci_spec->mounts[0]->destination);
++ ASSERT_EQ(oci_spec->mounts_len, 1);
++ ASSERT_EQ(strcmp(oci_spec->mounts[0]->destination, "/mount/path/1"), 0);
++
++ free_oci_runtime_spec(oci_spec);
++}
++
++TEST_F(SpecsUnitTest, test_spec_add_mount)
++{
++ defs_mount *mnt = (defs_mount *)util_common_calloc_s(sizeof(defs_mount));
++ ASSERT_NE(mnt, nullptr);
++ oci_runtime_spec *oci_spec = (oci_runtime_spec *)util_common_calloc_s(sizeof(oci_runtime_spec));
++ ASSERT_NE(oci_spec, nullptr);
++ oci_spec->mounts_len = 1;
++ oci_spec->mounts = (defs_mount **)util_common_calloc_s(sizeof(defs_mount *) * oci_spec->mounts_len );
++ ASSERT_NE(oci_spec->mounts, nullptr);
++
++ oci_spec->mounts[0] = (defs_mount *)util_common_calloc_s(sizeof(defs_mount));
++ ASSERT_NE(oci_spec->mounts[0], nullptr);
++ oci_spec->mounts[0]->destination = util_strdup_s("/mount/path/0");
++ ASSERT_EQ(spec_add_mount(oci_spec, mnt), 0);
++ ASSERT_EQ(oci_spec->mounts_len, 2);
++ ASSERT_EQ(oci_spec->mounts[1], mnt);
++
++ ASSERT_EQ(spec_add_mount(nullptr, mnt), -1);
++ ASSERT_EQ(spec_add_mount(oci_spec, nullptr), -1);
++
++ free_oci_runtime_spec(oci_spec);
++}
++
++#define TEST_SPEC_ADD_HOOKS_ITEM_DEF(hooktype) \
++ void test_spec_add_##hooktype##_hook(void) \
++ { \
++ defs_hook *hook = (defs_hook *)util_common_calloc_s(sizeof(defs_hook)); \
++ ASSERT_NE(hook, nullptr); \
++ oci_runtime_spec *oci_spec = (oci_runtime_spec *)util_common_calloc_s(sizeof(oci_runtime_spec)); \
++ ASSERT_NE(oci_spec, nullptr); \
++ oci_spec->hooks = (oci_runtime_spec_hooks *)util_common_calloc_s(sizeof(oci_runtime_spec_hooks)); \
++ ASSERT_NE(oci_spec->hooks, nullptr); \
++ oci_spec->hooks->hooktype##_len = 1; \
++ oci_spec->hooks->hooktype = (defs_hook **)util_common_calloc_s(sizeof(defs_hook *) * oci_spec->hooks->hooktype##_len); \
++ ASSERT_NE(oci_spec->hooks->hooktype, nullptr); \
++ \
++ oci_spec->hooks->hooktype[0] = (defs_hook *)util_common_calloc_s(sizeof(defs_hook)); \
++ ASSERT_NE(oci_spec->hooks->hooktype[0], nullptr); \
++ ASSERT_EQ(spec_add_##hooktype##_hook(oci_spec, hook), 0); \
++ ASSERT_EQ(oci_spec->hooks->hooktype##_len, 2); \
++ ASSERT_EQ(oci_spec->hooks->hooktype[1], hook); \
++ \
++ ASSERT_EQ(spec_add_##hooktype##_hook(nullptr, hook), -1); \
++ ASSERT_EQ(spec_add_##hooktype##_hook(oci_spec, nullptr), -1); \
++ \
++ free_oci_runtime_spec(oci_spec); \
++ }
++
++TEST_SPEC_ADD_HOOKS_ITEM_DEF(prestart)
++TEST_SPEC_ADD_HOOKS_ITEM_DEF(poststart)
++TEST_SPEC_ADD_HOOKS_ITEM_DEF(poststop)
++
++TEST_F(SpecsUnitTest, test_spec_add_hook)
++{
++ test_spec_add_prestart_hook();
++ test_spec_add_poststart_hook();
++ test_spec_add_poststop_hook();
++}
++
++#endif /* ENABLE_CDI */
++
+ /********************************* UT for merge caps *******************************************/
+ struct capabilities_lens {
+ size_t bounding_len;
+diff --git a/test/specs/specs_extend/CMakeLists.txt b/test/specs/specs_extend/CMakeLists.txt
+index 2fd37e1c..bd4d2dd6 100644
+--- a/test/specs/specs_extend/CMakeLists.txt
++++ b/test/specs/specs_extend/CMakeLists.txt
+@@ -44,6 +44,7 @@ add_executable(${EXE}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/storage_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/image_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/sender_mock.cc
++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/cdi_operate_api_mock.cc
+ specs_extend_ut.cc)
+
+ target_include_directories(${EXE} PUBLIC
+--
+2.25.1
+