915 lines
29 KiB
Diff
915 lines
29 KiB
Diff
From 907826d6d53c0fa1e2aa2c2abd175a12009f5839 Mon Sep 17 00:00:00 2001
|
|
From: zhongtao <zhongtao17@huawei.com>
|
|
Date: Sat, 13 May 2023 10:00:28 +0800
|
|
Subject: [PATCH 66/79] add ut for runc
|
|
|
|
Signed-off-by: zhongtao <zhongtao17@huawei.com>
|
|
---
|
|
test/cmd/CMakeLists.txt | 2 +-
|
|
test/cmd/isulad-shim/CMakeLists.txt | 22 +-
|
|
test/cmd/isulad-shim/common/CMakeLists.txt | 23 ++
|
|
test/cmd/isulad-shim/common/common_ut.cc | 344 ++++++++++++++++++
|
|
test/cmd/isulad-shim/isulad-shim_ut.cc | 123 -------
|
|
test/cmd/isulad-shim/process/CMakeLists.txt | 22 ++
|
|
test/cmd/isulad-shim/process/process_ut.cc | 49 +++
|
|
.../isulad-shim/shim-mainloop/CMakeLists.txt | 20 +
|
|
.../shim-mainloop/shim_mainloop_ut.cc | 55 +++
|
|
test/cutils/utils_utils/CMakeLists.txt | 2 +
|
|
test/cutils/utils_utils/utils_utils_ut.cc | 61 ++++
|
|
test/runtime/isula/isula_rt_ops_ut.cc | 59 +++
|
|
12 files changed, 639 insertions(+), 143 deletions(-)
|
|
create mode 100644 test/cmd/isulad-shim/common/CMakeLists.txt
|
|
create mode 100644 test/cmd/isulad-shim/common/common_ut.cc
|
|
delete mode 100644 test/cmd/isulad-shim/isulad-shim_ut.cc
|
|
create mode 100644 test/cmd/isulad-shim/process/CMakeLists.txt
|
|
create mode 100644 test/cmd/isulad-shim/process/process_ut.cc
|
|
create mode 100644 test/cmd/isulad-shim/shim-mainloop/CMakeLists.txt
|
|
create mode 100644 test/cmd/isulad-shim/shim-mainloop/shim_mainloop_ut.cc
|
|
|
|
diff --git a/test/cmd/CMakeLists.txt b/test/cmd/CMakeLists.txt
|
|
index 2d4cc751..cf0152ff 100644
|
|
--- a/test/cmd/CMakeLists.txt
|
|
+++ b/test/cmd/CMakeLists.txt
|
|
@@ -1,4 +1,4 @@
|
|
project(iSulad_UT)
|
|
|
|
add_subdirectory(isula)
|
|
-add_subdirectory(isulad-shim)
|
|
+add_subdirectory(isulad-shim)
|
|
\ No newline at end of file
|
|
diff --git a/test/cmd/isulad-shim/CMakeLists.txt b/test/cmd/isulad-shim/CMakeLists.txt
|
|
index 122538ff..47d03350 100644
|
|
--- a/test/cmd/isulad-shim/CMakeLists.txt
|
|
+++ b/test/cmd/isulad-shim/CMakeLists.txt
|
|
@@ -1,21 +1,5 @@
|
|
project(iSulad_UT)
|
|
|
|
-SET(EXE isulad-shim_ut)
|
|
-
|
|
-add_executable(${EXE}
|
|
- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim/process.c
|
|
- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim/common.c
|
|
- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim/terminal.c
|
|
- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim/mainloop.c
|
|
- isulad-shim_ut.cc)
|
|
-
|
|
-target_include_directories(${EXE} PUBLIC
|
|
- ${GTEST_INCLUDE_DIR}
|
|
- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/cmd/isulad-shim
|
|
- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/common
|
|
- ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256
|
|
- ${CMAKE_BINARY_DIR}/conf
|
|
- )
|
|
-target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} -lcrypto -lyajl -lz)
|
|
-add_test(NAME ${EXE} COMMAND ${EXE} --gtest_output=xml:${EXE}-Results.xml)
|
|
-set_tests_properties(${EXE} PROPERTIES TIMEOUT 120)
|
|
+add_subdirectory(shim-mainloop)
|
|
+add_subdirectory(process)
|
|
+add_subdirectory(common)
|
|
\ No newline at end of file
|
|
diff --git a/test/cmd/isulad-shim/common/CMakeLists.txt b/test/cmd/isulad-shim/common/CMakeLists.txt
|
|
new file mode 100644
|
|
index 00000000..94ec2703
|
|
--- /dev/null
|
|
+++ b/test/cmd/isulad-shim/common/CMakeLists.txt
|
|
@@ -0,0 +1,23 @@
|
|
+project(iSulad_UT)
|
|
+
|
|
+SET(EXE common_ut)
|
|
+
|
|
+add_executable(${EXE}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/process.c
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/common.c
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/terminal.c
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/mainloop.c
|
|
+ common_ut.cc)
|
|
+
|
|
+target_include_directories(${EXE} PUBLIC
|
|
+ ${GTEST_INCLUDE_DIR}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/common
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/sha256
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include
|
|
+ ${CMAKE_BINARY_DIR}/conf
|
|
+ )
|
|
+set_target_properties(${EXE} PROPERTIES LINK_FLAGS "-Wl,--wrap,calloc")
|
|
+target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} -lcrypto -lyajl -lz)
|
|
+add_test(NAME ${EXE} COMMAND ${EXE} --gtest_output=xml:${EXE}-Results.xml)
|
|
+set_tests_properties(${EXE} PROPERTIES TIMEOUT 120)
|
|
\ No newline at end of file
|
|
diff --git a/test/cmd/isulad-shim/common/common_ut.cc b/test/cmd/isulad-shim/common/common_ut.cc
|
|
new file mode 100644
|
|
index 00000000..cb790b21
|
|
--- /dev/null
|
|
+++ b/test/cmd/isulad-shim/common/common_ut.cc
|
|
@@ -0,0 +1,344 @@
|
|
+/*
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-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.
|
|
+ * Description: common unit test
|
|
+ * Author: leizhongkai
|
|
+ * Create: 2020-02-25
|
|
+ */
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+#include <gtest/gtest.h>
|
|
+#include <gmock/gmock.h>
|
|
+#include "mock.h"
|
|
+
|
|
+#include "mainloop.h"
|
|
+#include "process.h"
|
|
+#include "common.h"
|
|
+
|
|
+using ::testing::Args;
|
|
+using ::testing::ByRef;
|
|
+using ::testing::SetArgPointee;
|
|
+using ::testing::DoAll;
|
|
+using ::testing::NiceMock;
|
|
+using ::testing::Return;
|
|
+using ::testing::NotNull;
|
|
+using ::testing::AtLeast;
|
|
+using ::testing::Invoke;
|
|
+using ::testing::_;
|
|
+
|
|
+using namespace std;
|
|
+
|
|
+extern "C" {
|
|
+ DECLARE_WRAPPER(calloc, void *, (size_t nmemb, size_t size));
|
|
+ DEFINE_WRAPPER(calloc, void *, (size_t nmemb, size_t size), (nmemb, size));
|
|
+}
|
|
+
|
|
+class CommonUnitTest : public testing::Test {
|
|
+public:
|
|
+ void SetUp() override
|
|
+ {
|
|
+ }
|
|
+ void TearDown() override
|
|
+ {
|
|
+ }
|
|
+};
|
|
+
|
|
+TEST(shim, test_signal_routine)
|
|
+{
|
|
+ signal_routine(SIGCONT);
|
|
+}
|
|
+
|
|
+TEST_F(CommonUnitTest, test_open_no_inherit)
|
|
+{
|
|
+ string exist_file = "/tmp/test_open_no_inherit_exist";
|
|
+ string non_file = "/tmp/test_open_no_inherit_non";
|
|
+ int fd_exist = -1;
|
|
+
|
|
+ fd_exist = open_no_inherit(exist_file.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640);
|
|
+ EXPECT_GT(fd_exist, 0);
|
|
+ EXPECT_EQ(open_no_inherit(non_file.c_str(), O_WRONLY, -1), -1);
|
|
+
|
|
+ close(fd_exist);
|
|
+ unlink(exist_file.c_str());
|
|
+}
|
|
+
|
|
+TEST_F(CommonUnitTest, test_read_write_nointr)
|
|
+{
|
|
+ char buf[32] = { 0 };
|
|
+ string test_file = "/tmp/test_read_nointr";
|
|
+ string test_string = "hello";
|
|
+ int fd_wr = -1;
|
|
+ int fd_rd = -1;
|
|
+ int nwrite = -1;
|
|
+ int nread = -1;
|
|
+
|
|
+ EXPECT_EQ(read_nointr(-1, nullptr, 32), -1);
|
|
+ EXPECT_EQ(read_nointr(0, nullptr, 32), -1);
|
|
+ EXPECT_EQ(read_nointr(1, nullptr, 32), -1);
|
|
+
|
|
+ fd_wr = open_no_inherit(test_file.c_str(), O_CREAT | O_RDWR | O_APPEND | O_SYNC, 0640);
|
|
+ EXPECT_GT(fd_wr, 0);
|
|
+ nwrite = write_nointr_in_total(fd_wr, test_string.c_str(), 5);
|
|
+ EXPECT_EQ(nwrite, 5);
|
|
+ fd_rd = open(test_file.c_str(), O_RDONLY);
|
|
+ nread = read_nointr(fd_rd, buf, 32);
|
|
+ EXPECT_EQ(nread, 5);
|
|
+
|
|
+ close(fd_wr);
|
|
+ close(fd_rd);
|
|
+ unlink(test_file.c_str());
|
|
+}
|
|
+
|
|
+TEST_F(CommonUnitTest, test_file_exist)
|
|
+{
|
|
+ string exist_file = "/tmp/test_exist_exist";
|
|
+ string non_file = "/tmp/test_exist_non";
|
|
+ int fd_exist = -1;
|
|
+
|
|
+ fd_exist = open_no_inherit(exist_file.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640);
|
|
+ EXPECT_GT(fd_exist, 0);
|
|
+ EXPECT_TRUE(file_exists(exist_file.c_str()));
|
|
+ EXPECT_FALSE(file_exists(non_file.c_str()));
|
|
+
|
|
+ close(fd_exist);
|
|
+ unlink(exist_file.c_str());
|
|
+}
|
|
+
|
|
+
|
|
+TEST_F(CommonUnitTest, test_combined_output)
|
|
+{
|
|
+ string exist_cmd = "ls";
|
|
+ string non_cmd = "aaa";
|
|
+ const char *params[MAX_RUNTIME_ARGS] = { nullptr };
|
|
+ char output[BUFSIZ] = { 0 };
|
|
+ int output_len = BUFSIZ;
|
|
+
|
|
+ params[0] = exist_cmd.c_str();
|
|
+ EXPECT_EQ(cmd_combined_output(exist_cmd.c_str(), params, output, &output_len), 0);
|
|
+
|
|
+ params[0] = non_cmd.c_str();
|
|
+ EXPECT_EQ(cmd_combined_output(non_cmd.c_str(), params, output, &output_len), -1);
|
|
+}
|
|
+
|
|
+TEST_F(CommonUnitTest, test_util_array_len)
|
|
+{
|
|
+ const char *array_long[] = { "abcd", "1234", "a1b", nullptr };
|
|
+
|
|
+ ASSERT_EQ(util_array_len(nullptr), 0);
|
|
+
|
|
+ ASSERT_EQ(util_array_len(array_long), 3);
|
|
+}
|
|
+
|
|
+TEST_F(CommonUnitTest, test_util_free_array)
|
|
+{
|
|
+ char **array = nullptr;
|
|
+
|
|
+ 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[3] = nullptr;
|
|
+
|
|
+ util_free_array(nullptr);
|
|
+ util_free_array(array);
|
|
+}
|
|
+
|
|
+TEST(utils_array, test_util_grow_array)
|
|
+{
|
|
+ char **array = nullptr;
|
|
+ size_t capacity = 0;
|
|
+ int ret;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(&array, &capacity, 1, 1);
|
|
+ ASSERT_EQ(ret, 0);
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ASSERT_EQ(array[0], nullptr);
|
|
+ ASSERT_EQ(array[1], nullptr);
|
|
+ ASSERT_EQ(capacity, 2);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(capacity * sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(&array, &capacity, 1, 2);
|
|
+ ASSERT_EQ(ret, 0);
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ASSERT_EQ(array[0], nullptr);
|
|
+ ASSERT_EQ(array[1], nullptr);
|
|
+ ASSERT_EQ(array[2], nullptr);
|
|
+ ASSERT_EQ(capacity, 3);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(capacity * sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(&array, &capacity, 1, 4);
|
|
+ ASSERT_EQ(ret, 0);
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ASSERT_EQ(array[0], nullptr);
|
|
+ ASSERT_EQ(array[1], nullptr);
|
|
+ ASSERT_EQ(array[2], nullptr);
|
|
+ ASSERT_EQ(array[3], nullptr);
|
|
+ ASSERT_EQ(array[4], nullptr);
|
|
+ ASSERT_EQ(capacity, 5);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(capacity * sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(&array, &capacity, 1, 0);
|
|
+ ASSERT_NE(ret, 0);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(capacity * sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(&array, &capacity, 4, 1);
|
|
+ ASSERT_EQ(ret, 0);
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ASSERT_EQ(array[0], nullptr);
|
|
+ ASSERT_EQ(array[1], nullptr);
|
|
+ ASSERT_EQ(array[2], nullptr);
|
|
+ ASSERT_EQ(array[3], nullptr);
|
|
+ ASSERT_EQ(array[4], nullptr);
|
|
+ ASSERT_EQ(capacity, 5);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(capacity * sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(&array, &capacity, 0, 1);
|
|
+ ASSERT_EQ(ret, 0);
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ASSERT_EQ(array[0], nullptr);
|
|
+ ASSERT_EQ(capacity, 1);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(capacity * sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(&array, nullptr, 1, 1);
|
|
+ ASSERT_NE(ret, 0);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+
|
|
+ capacity = 1;
|
|
+ array = (char **)util_common_calloc_s(capacity * sizeof(char *));
|
|
+ ASSERT_NE(array, nullptr);
|
|
+ ret = util_grow_array(nullptr, &capacity, 1, 1);
|
|
+ ASSERT_NE(ret, 0);
|
|
+ util_free_array(array);
|
|
+ array = nullptr;
|
|
+ capacity = 0;
|
|
+}
|
|
+
|
|
+TEST(utils_string_ut, test_util_string_split_multi)
|
|
+{
|
|
+ char **result = nullptr;
|
|
+
|
|
+ result = util_string_split_multi("abcd,,,1234999999999", ',');
|
|
+ ASSERT_NE(result, nullptr);
|
|
+ ASSERT_STREQ(result[0], "abcd");
|
|
+ free(result[0]);
|
|
+ ASSERT_STREQ(result[1], "");
|
|
+ free(result[1]);
|
|
+ ASSERT_STREQ(result[2], "");
|
|
+ free(result[2]);
|
|
+ ASSERT_STREQ(result[3], "1234999999999");
|
|
+ free(result[3]);
|
|
+ ASSERT_STREQ(result[4], nullptr);
|
|
+ free(result);
|
|
+
|
|
+ result = util_string_split_multi("abcd,1234,*&^(,defgz", ',');
|
|
+ ASSERT_NE(result, nullptr);
|
|
+ ASSERT_STREQ(result[0], "abcd");
|
|
+ free(result[0]);
|
|
+ ASSERT_STREQ(result[1], "1234");
|
|
+ free(result[1]);
|
|
+ ASSERT_STREQ(result[2], "*&^(");
|
|
+ free(result[2]);
|
|
+ ASSERT_STREQ(result[3], "defgz");
|
|
+ free(result[3]);
|
|
+ ASSERT_STREQ(result[4], nullptr);
|
|
+ free(result);
|
|
+
|
|
+ result = util_string_split_multi(",abcd,12340000000000", ',');
|
|
+ ASSERT_NE(result, nullptr);
|
|
+ ASSERT_STREQ(result[0], "");
|
|
+ free(result[0]);
|
|
+ ASSERT_STREQ(result[1], "abcd");
|
|
+ free(result[1]);
|
|
+ ASSERT_STREQ(result[2], "12340000000000");
|
|
+ free(result[2]);
|
|
+ ASSERT_STREQ(result[3], nullptr);
|
|
+ free(result);
|
|
+
|
|
+ result = util_string_split_multi("abcd,12340000000000,", ',');
|
|
+ ASSERT_NE(result, nullptr);
|
|
+ ASSERT_STREQ(result[0], "abcd");
|
|
+ free(result[0]);
|
|
+ ASSERT_STREQ(result[1], "12340000000000");
|
|
+ free(result[1]);
|
|
+ ASSERT_STREQ(result[2], "");
|
|
+ free(result[2]);
|
|
+ ASSERT_STREQ(result[3], nullptr);
|
|
+ free(result);
|
|
+
|
|
+ result = util_string_split_multi("abcd,1234,", 'x');
|
|
+ ASSERT_NE(result, nullptr);
|
|
+ ASSERT_STREQ(result[0], "abcd,1234,");
|
|
+ free(result[0]);
|
|
+ ASSERT_STREQ(result[1], nullptr);
|
|
+ free(result);
|
|
+
|
|
+ result = util_string_split_multi(",", ',');
|
|
+ ASSERT_NE(result, nullptr);
|
|
+ ASSERT_STREQ(result[0], "");
|
|
+ free(result[0]);
|
|
+ ASSERT_STREQ(result[1], "");
|
|
+ free(result[1]);
|
|
+ ASSERT_STREQ(result[2], nullptr);
|
|
+ free(result);
|
|
+
|
|
+ result = util_string_split_multi("", ',');
|
|
+ ASSERT_NE(result, nullptr);
|
|
+ ASSERT_STREQ(result[0], "");
|
|
+ free(result[0]);
|
|
+ ASSERT_STREQ(result[1], nullptr);
|
|
+ free(result);
|
|
+
|
|
+ result = util_string_split_multi(nullptr, ',');
|
|
+ ASSERT_EQ(result, nullptr);
|
|
+
|
|
+ MOCK_SET(calloc, nullptr);
|
|
+ result = util_string_split_multi("abcd,12340000000000,", ',');
|
|
+ ASSERT_EQ(result, nullptr);
|
|
+ MOCK_CLEAR(calloc);
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/test/cmd/isulad-shim/isulad-shim_ut.cc b/test/cmd/isulad-shim/isulad-shim_ut.cc
|
|
deleted file mode 100644
|
|
index 8c116ac8..00000000
|
|
--- a/test/cmd/isulad-shim/isulad-shim_ut.cc
|
|
+++ /dev/null
|
|
@@ -1,123 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
|
|
- * Description: isulad-shim unit test
|
|
- * Author: leizhongkai
|
|
- * Create: 2020-02-25
|
|
- */
|
|
-#include <sys/types.h>
|
|
-#include <sys/stat.h>
|
|
-#include <fcntl.h>
|
|
-#include <unistd.h>
|
|
-#include <gtest/gtest.h>
|
|
-#include <gmock/gmock.h>
|
|
-
|
|
-#include "mainloop.h"
|
|
-#include "process.h"
|
|
-#include "common.h"
|
|
-
|
|
-int g_log_fd = -1;
|
|
-
|
|
-using ::testing::Args;
|
|
-using ::testing::ByRef;
|
|
-using ::testing::SetArgPointee;
|
|
-using ::testing::DoAll;
|
|
-using ::testing::NiceMock;
|
|
-using ::testing::Return;
|
|
-using ::testing::NotNull;
|
|
-using ::testing::AtLeast;
|
|
-using ::testing::Invoke;
|
|
-using ::testing::_;
|
|
-
|
|
-using namespace std;
|
|
-
|
|
-class IsuladShimUnitTest : public testing::Test {
|
|
-public:
|
|
- void SetUp() override
|
|
- {
|
|
- }
|
|
- void TearDown() override
|
|
- {
|
|
- }
|
|
-};
|
|
-
|
|
-TEST_F(IsuladShimUnitTest, test_new_process)
|
|
-{
|
|
- string id = "aaaabbbbccccdddd";
|
|
- string bundle = "/home/isulad/bundle";
|
|
- string runtime = "kata-runtime";
|
|
-
|
|
- process_t *p = new_process((char*)id.c_str(), (char*)bundle.c_str(), (char*)runtime.c_str());
|
|
- ASSERT_TRUE(p == nullptr);
|
|
-}
|
|
-
|
|
-TEST_F(IsuladShimUnitTest, test_open_no_inherit)
|
|
-{
|
|
- string exist_file = "/tmp/test_open_no_inherit_exist";
|
|
- string non_file = "/tmp/test_open_no_inherit_non";
|
|
- int fd_exist = -1;
|
|
-
|
|
- fd_exist = open_no_inherit(exist_file.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640);
|
|
- EXPECT_GT(fd_exist, 0);
|
|
- EXPECT_EQ(open_no_inherit(non_file.c_str(), O_WRONLY, -1), -1);
|
|
-
|
|
- close(fd_exist);
|
|
- unlink(exist_file.c_str());
|
|
-}
|
|
-
|
|
-TEST_F(IsuladShimUnitTest, test_read_write_nointr)
|
|
-{
|
|
- char buf[32] = { 0 };
|
|
- string test_file = "/tmp/test_read_nointr";
|
|
- string test_string = "hello";
|
|
- int fd_wr = -1;
|
|
- int fd_rd = -1;
|
|
- int nwrite = -1;
|
|
- int nread = -1;
|
|
-
|
|
- EXPECT_EQ(read_nointr(-1, nullptr, 32), -1);
|
|
- EXPECT_EQ(read_nointr(0, nullptr, 32), -1);
|
|
- EXPECT_EQ(read_nointr(1, nullptr, 32), -1);
|
|
-
|
|
- fd_wr = open_no_inherit(test_file.c_str(), O_CREAT | O_RDWR | O_APPEND | O_SYNC, 0640);
|
|
- EXPECT_GT(fd_wr, 0);
|
|
- nwrite = write_nointr_in_total(fd_wr, test_string.c_str(), 5);
|
|
- EXPECT_EQ(nwrite, 5);
|
|
- fd_rd = open(test_file.c_str(), O_RDONLY);
|
|
- nread = read_nointr(fd_rd, buf, 32);
|
|
- EXPECT_EQ(nread, 5);
|
|
-
|
|
- close(fd_wr);
|
|
- close(fd_rd);
|
|
- unlink(test_file.c_str());
|
|
-}
|
|
-
|
|
-TEST_F(IsuladShimUnitTest, test_file_exist)
|
|
-{
|
|
- string exist_file = "/tmp/test_exist_exist";
|
|
- string non_file = "/tmp/test_exist_non";
|
|
- int fd_exist = -1;
|
|
-
|
|
- fd_exist = open_no_inherit(exist_file.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0640);
|
|
- EXPECT_GT(fd_exist, 0);
|
|
- EXPECT_TRUE(file_exists(exist_file.c_str()));
|
|
- EXPECT_FALSE(file_exists(non_file.c_str()));
|
|
-
|
|
- close(fd_exist);
|
|
- unlink(exist_file.c_str());
|
|
-}
|
|
-
|
|
-
|
|
-TEST_F(IsuladShimUnitTest, test_combined_output)
|
|
-{
|
|
- string exist_cmd = "ls";
|
|
- string non_cmd = "aaa";
|
|
- const char *params[MAX_RUNTIME_ARGS] = { nullptr };
|
|
- char output[BUFSIZ] = { 0 };
|
|
- int output_len = BUFSIZ;
|
|
-
|
|
- params[0] = exist_cmd.c_str();
|
|
- EXPECT_EQ(cmd_combined_output(exist_cmd.c_str(), params, output, &output_len), 0);
|
|
-
|
|
- params[0] = non_cmd.c_str();
|
|
- EXPECT_EQ(cmd_combined_output(non_cmd.c_str(), params, output, &output_len), -1);
|
|
-}
|
|
diff --git a/test/cmd/isulad-shim/process/CMakeLists.txt b/test/cmd/isulad-shim/process/CMakeLists.txt
|
|
new file mode 100644
|
|
index 00000000..dc96dc01
|
|
--- /dev/null
|
|
+++ b/test/cmd/isulad-shim/process/CMakeLists.txt
|
|
@@ -0,0 +1,22 @@
|
|
+project(iSulad_UT)
|
|
+
|
|
+SET(EXE process_ut)
|
|
+
|
|
+add_executable(${EXE}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/mainloop_mock.cc
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/mainloop.c
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/common.c
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/process.c
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/terminal.c
|
|
+ process_ut.cc)
|
|
+
|
|
+target_include_directories(${EXE} PUBLIC
|
|
+ ${GTEST_INCLUDE_DIR}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks
|
|
+ )
|
|
+
|
|
+target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} -lcrypto -lyajl -lz)
|
|
+add_test(NAME ${EXE} COMMAND ${EXE} --gtest_output=xml:${EXE}-Results.xml)
|
|
+set_tests_properties(${EXE} PROPERTIES TIMEOUT 120)
|
|
\ No newline at end of file
|
|
diff --git a/test/cmd/isulad-shim/process/process_ut.cc b/test/cmd/isulad-shim/process/process_ut.cc
|
|
new file mode 100644
|
|
index 00000000..292d5b2c
|
|
--- /dev/null
|
|
+++ b/test/cmd/isulad-shim/process/process_ut.cc
|
|
@@ -0,0 +1,49 @@
|
|
+/*
|
|
+ * 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.
|
|
+ * Description: process unit test
|
|
+ * Author: leizhongkai
|
|
+ * Create: 2020-02-25
|
|
+ */
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+#include <gtest/gtest.h>
|
|
+#include <gmock/gmock.h>
|
|
+
|
|
+#include "mainloop.h"
|
|
+#include "process.h"
|
|
+#include "common.h"
|
|
+
|
|
+
|
|
+using ::testing::Args;
|
|
+using ::testing::ByRef;
|
|
+using ::testing::SetArgPointee;
|
|
+using ::testing::DoAll;
|
|
+using ::testing::NiceMock;
|
|
+using ::testing::Return;
|
|
+using ::testing::NotNull;
|
|
+using ::testing::AtLeast;
|
|
+using ::testing::Invoke;
|
|
+using ::testing::_;
|
|
+
|
|
+using namespace std;
|
|
+
|
|
+TEST(process, test_new_process)
|
|
+{
|
|
+ string id = "aaaabbbbccccdddd";
|
|
+ string bundle = "/home/isulad/bundle";
|
|
+ string runtime = "kata-runtime";
|
|
+
|
|
+ process_t *p = new_process((char*)id.c_str(), (char*)bundle.c_str(), (char*)runtime.c_str());
|
|
+ ASSERT_TRUE(p == nullptr);
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/test/cmd/isulad-shim/shim-mainloop/CMakeLists.txt b/test/cmd/isulad-shim/shim-mainloop/CMakeLists.txt
|
|
new file mode 100644
|
|
index 00000000..457720ad
|
|
--- /dev/null
|
|
+++ b/test/cmd/isulad-shim/shim-mainloop/CMakeLists.txt
|
|
@@ -0,0 +1,20 @@
|
|
+project(iSulad_UT)
|
|
+
|
|
+SET(EXE shim_mainloop_ut)
|
|
+
|
|
+add_executable(${EXE}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks/mainloop_mock.cc
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/mainloop.c
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim/common.c
|
|
+ shim_mainloop_ut.cc)
|
|
+
|
|
+target_include_directories(${EXE} PUBLIC
|
|
+ ${GTEST_INCLUDE_DIR}
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/cmd/isulad-shim
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include
|
|
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../test/mocks
|
|
+ )
|
|
+
|
|
+target_link_libraries(${EXE} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} -lcrypto -lyajl -lz)
|
|
+add_test(NAME ${EXE} COMMAND ${EXE} --gtest_output=xml:${EXE}-Results.xml)
|
|
+set_tests_properties(${EXE} PROPERTIES TIMEOUT 120)
|
|
\ No newline at end of file
|
|
diff --git a/test/cmd/isulad-shim/shim-mainloop/shim_mainloop_ut.cc b/test/cmd/isulad-shim/shim-mainloop/shim_mainloop_ut.cc
|
|
new file mode 100644
|
|
index 00000000..ec3815c3
|
|
--- /dev/null
|
|
+++ b/test/cmd/isulad-shim/shim-mainloop/shim_mainloop_ut.cc
|
|
@@ -0,0 +1,55 @@
|
|
+/*
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2022. 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.
|
|
+ * Description: mainloop unit test
|
|
+ * Author: zhangxiaoyu
|
|
+ * Create: 2022-10-11
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <gtest/gtest.h>
|
|
+#include "mainloop.h"
|
|
+#include "mainloop_mock.h"
|
|
+
|
|
+using ::testing::NiceMock;
|
|
+using ::testing::Invoke;
|
|
+using ::testing::Return;
|
|
+using ::testing::_;
|
|
+
|
|
+class ShimMainloopUnitTest : public testing::Test {
|
|
+protected:
|
|
+ void SetUp() override
|
|
+ {
|
|
+ Mainloop_SetMock(&m_mainloop_mock);
|
|
+ EXPECT_CALL(m_mainloop_mock, Close(_)).WillRepeatedly(Return(0));
|
|
+ EXPECT_CALL(m_mainloop_mock, EpollCreate1(_)).WillRepeatedly(Return(0));
|
|
+ EXPECT_CALL(m_mainloop_mock, EpollCtl(_, _, _, _)).WillRepeatedly(Return(0));
|
|
+ EXPECT_CALL(m_mainloop_mock, EpollWait(_, _, _, _)).WillRepeatedly(Return(0));
|
|
+ }
|
|
+
|
|
+ void TearDown() override
|
|
+ {
|
|
+ Mainloop_SetMock(nullptr);
|
|
+ }
|
|
+
|
|
+ NiceMock<MockMainloop> m_mainloop_mock;
|
|
+};
|
|
+
|
|
+TEST_F(ShimMainloopUnitTest, test_mainloop)
|
|
+{
|
|
+ struct epoll_descr descr = { 0 };
|
|
+
|
|
+ ASSERT_EQ(epoll_loop_open(&descr), 0);
|
|
+ ASSERT_EQ(epoll_loop_add_handler(&descr, 111, nullptr, nullptr), 0);
|
|
+ ASSERT_EQ(epoll_loop(&descr, -1), 0);
|
|
+ ASSERT_EQ(epoll_loop_del_handler(&descr, 111), 0);
|
|
+ ASSERT_EQ(epoll_loop_close(&descr), 0);
|
|
+}
|
|
diff --git a/test/cutils/utils_utils/CMakeLists.txt b/test/cutils/utils_utils/CMakeLists.txt
|
|
index 99a83e7a..6d276390 100644
|
|
--- a/test/cutils/utils_utils/CMakeLists.txt
|
|
+++ b/test/cutils/utils_utils/CMakeLists.txt
|
|
@@ -12,6 +12,8 @@ target_include_directories(${EXE} PUBLIC
|
|
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/map
|
|
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils
|
|
)
|
|
+
|
|
+set_target_properties(${EXE} PROPERTIES LINK_FLAGS "-Wl,--wrap,waitpid")
|
|
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_utils/utils_utils_ut.cc b/test/cutils/utils_utils/utils_utils_ut.cc
|
|
index 6c7ece24..79583174 100644
|
|
--- a/test/cutils/utils_utils/utils_utils_ut.cc
|
|
+++ b/test/cutils/utils_utils/utils_utils_ut.cc
|
|
@@ -15,6 +15,44 @@
|
|
|
|
#include <gtest/gtest.h>
|
|
#include "utils.h"
|
|
+#include "mock.h"
|
|
+
|
|
+static pid_t test_pid = -1;
|
|
+
|
|
+extern "C" {
|
|
+ DECLARE_WRAPPER_V(waitpid, pid_t, (__pid_t pid, int *stat_loc, int options));
|
|
+ DEFINE_WRAPPER_V(waitpid, pid_t, (__pid_t pid, int *stat_loc, int options),(pid, stat_loc, options));
|
|
+}
|
|
+
|
|
+static pid_t waitpid_none_zero(__pid_t pid, int *stat_loc, int options)
|
|
+{
|
|
+ *stat_loc = 256;
|
|
+ return test_pid;
|
|
+}
|
|
+
|
|
+static pid_t waitpid_zero(__pid_t pid, int *stat_loc, int options)
|
|
+{
|
|
+ *stat_loc = 0;
|
|
+ return test_pid;
|
|
+}
|
|
+
|
|
+#define ExitSignalOffset 128
|
|
+static int status_to_exit_code(int status)
|
|
+{
|
|
+ int exit_code = 0;
|
|
+
|
|
+ if (WIFEXITED(status)) {
|
|
+ exit_code = WEXITSTATUS(status);
|
|
+ } else {
|
|
+ exit_code = -1;
|
|
+ }
|
|
+ if (WIFSIGNALED(status)) {
|
|
+ int signal;
|
|
+ signal = WTERMSIG(status);
|
|
+ exit_code = ExitSignalOffset + signal;
|
|
+ }
|
|
+ return exit_code;
|
|
+}
|
|
|
|
TEST(utils_utils, test_util_mem_realloc)
|
|
{
|
|
@@ -297,4 +335,27 @@ TEST(utils_utils, test_do_retry_call)
|
|
DO_RETRY_CALL(10, 100, nret, retry_call_test, 11);
|
|
ASSERT_EQ(global_total, 10);
|
|
ASSERT_EQ(nret, -1);
|
|
+}
|
|
+
|
|
+TEST(utils_utils, test_util_waitpid_with_timeout)
|
|
+{
|
|
+ int64_t timeout = 2;
|
|
+ pid_t pid = getpid();
|
|
+ int status = 0;
|
|
+
|
|
+ test_pid = pid;
|
|
+ MOCK_SET_V(waitpid, waitpid_none_zero);
|
|
+ status = util_waitpid_with_timeout(test_pid, timeout, nullptr);
|
|
+ ASSERT_EQ(status, 256);
|
|
+ ASSERT_EQ(status_to_exit_code(status), 1);
|
|
+ MOCK_CLEAR(waitpid);
|
|
+
|
|
+ MOCK_SET_V(waitpid, waitpid_zero);
|
|
+ status = util_waitpid_with_timeout(test_pid, timeout, nullptr);
|
|
+ ASSERT_EQ(status, 0);
|
|
+ ASSERT_EQ(status_to_exit_code(status), 0);
|
|
+ MOCK_CLEAR(waitpid);
|
|
+
|
|
+ ASSERT_EQ(util_waitpid_with_timeout(pid, timeout, nullptr), -1);
|
|
+
|
|
}
|
|
\ No newline at end of file
|
|
diff --git a/test/runtime/isula/isula_rt_ops_ut.cc b/test/runtime/isula/isula_rt_ops_ut.cc
|
|
index 03c213a5..9e014ac3 100644
|
|
--- a/test/runtime/isula/isula_rt_ops_ut.cc
|
|
+++ b/test/runtime/isula/isula_rt_ops_ut.cc
|
|
@@ -163,3 +163,62 @@ TEST_F(IsulaRtOpsUnitTest, test_rt_isula_exec_resize)
|
|
close(fd);
|
|
ASSERT_EQ(system(rm_path.c_str()), 0);
|
|
}
|
|
+
|
|
+TEST_F(IsulaRtOpsUnitTest, test_rt_isula_update)
|
|
+{
|
|
+ rt_update_params_t params = {};
|
|
+ ASSERT_EQ(rt_isula_update(nullptr, nullptr, nullptr), -1);
|
|
+
|
|
+ ASSERT_EQ(rt_isula_update("123", nullptr, nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_update("123", "runtime", nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_update("123", "runtime", ¶ms), -1);
|
|
+}
|
|
+
|
|
+TEST_F(IsulaRtOpsUnitTest, test_rt_isula_pause)
|
|
+{
|
|
+ rt_pause_params_t params = {};
|
|
+ ASSERT_EQ(rt_isula_pause(nullptr, nullptr, nullptr), -1);
|
|
+
|
|
+ ASSERT_EQ(rt_isula_pause("123", nullptr, nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_pause("123", "runtime", nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_pause("123", "runtime", ¶ms), -1);
|
|
+}
|
|
+
|
|
+TEST_F(IsulaRtOpsUnitTest, test_rt_isula_resume)
|
|
+{
|
|
+ rt_resume_params_t params = {};
|
|
+ ASSERT_EQ(rt_isula_resume(nullptr, nullptr, nullptr), -1);
|
|
+
|
|
+ ASSERT_EQ(rt_isula_resume("123", nullptr, nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_resume("123", "runtime", nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_resume("123", "runtime", ¶ms), -1);
|
|
+}
|
|
+
|
|
+TEST_F(IsulaRtOpsUnitTest, test_rt_isula_resources_stats)
|
|
+{
|
|
+ rt_stats_params_t params = {};
|
|
+ struct runtime_container_resources_stats_info stats = {};
|
|
+
|
|
+ ASSERT_EQ(rt_isula_resources_stats(nullptr, nullptr, nullptr, nullptr), -1);
|
|
+
|
|
+ ASSERT_EQ(rt_isula_resources_stats("123", nullptr, nullptr, nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_resources_stats("123", "runtime", nullptr, nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_resources_stats("123", "runtime", ¶ms, nullptr), -1);
|
|
+ params.state = "/var/run/isulad/runtime";
|
|
+ ASSERT_EQ(rt_isula_resources_stats("123", "runtime", ¶ms, &stats), -1);
|
|
+}
|
|
+
|
|
+TEST_F(IsulaRtOpsUnitTest, test_rt_isula_kill)
|
|
+{
|
|
+ rt_kill_params_t kill_params = {
|
|
+ .signal = SIGTERM,
|
|
+ .stop_signal = SIGKILL,
|
|
+ .pid = -1,
|
|
+ .start_time = 12345,
|
|
+ };
|
|
+ ASSERT_EQ(rt_isula_kill(nullptr, nullptr, nullptr), -1);
|
|
+
|
|
+ ASSERT_EQ(rt_isula_kill("123", nullptr, nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_kill("123", "runtime", nullptr), -1);
|
|
+ ASSERT_EQ(rt_isula_kill("123", "runtime", &kill_params), -1);
|
|
+}
|
|
\ No newline at end of file
|
|
--
|
|
2.25.1
|
|
|