This commit adds unit tests for cgroup_create_cgroup(). [----------] 3 tests from CgroupCreateCgroupTest [ RUN ] CgroupCreateCgroupTest.CgroupCreateCgroupV1 [ OK ] CgroupCreateCgroupTest.CgroupCreateCgroupV1 (1 ms) [ RUN ] CgroupCreateCgroupTest.CgroupCreateCgroupV2 [ OK ] CgroupCreateCgroupTest.CgroupCreateCgroupV2 (0 ms) [ RUN ] CgroupCreateCgroupTest.CgroupCreateCgroupV1AndV2 [ OK ] CgroupCreateCgroupTest.CgroupCreateCgroupV1AndV2 (1 ms) [----------] 3 tests from CgroupCreateCgroupTest (2 ms total)
Signed-off-by: Tom Hromatka <tom.hroma...@oracle.com> --- gunit/012-cgroup_create_cgroup.cpp | 232 +++++++++++++++++++++++++++++ gunit/Makefile.am | 3 +- 2 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 gunit/012-cgroup_create_cgroup.cpp diff --git a/gunit/012-cgroup_create_cgroup.cpp b/gunit/012-cgroup_create_cgroup.cpp new file mode 100644 index 000000000000..d3752c23c0d8 --- /dev/null +++ b/gunit/012-cgroup_create_cgroup.cpp @@ -0,0 +1,232 @@ +/** + * libcgroup googletest for cgroup_create_cgroup() + * + * Copyright (c) 2020 Oracle and/or its affiliates. + * Author: Tom Hromatka <tom.hroma...@oracle.com> + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see <http://www.gnu.org/licenses>. + */ + +#include <dirent.h> +#include <ftw.h> + +#include "gtest/gtest.h" +#include "libcgroup-internal.h" + +static const char * const PARENT_DIR = "test012cgroup"; +static const mode_t MODE = S_IRWXU | S_IRWXG | S_IRWXO; + +static const char * const CONTROLLERS[] = { + "cpu", + "freezer", + "memory", + "cpuset", + "namespaces", + "netns", +}; +static const int CONTROLLERS_CNT = + sizeof(CONTROLLERS) / sizeof(CONTROLLERS[0]); + +static cg_version_t VERSIONS[] = { + CGROUP_V1, + CGROUP_V2, + CGROUP_V2, + CGROUP_V1, + CGROUP_V1, + CGROUP_V2, +}; +static const int VERSIONS_CNT = + sizeof(VERSIONS) / sizeof(VERSIONS[0]); + +class CgroupCreateCgroupTest : public ::testing::Test { + protected: + + void SetUp() override + { + char tmp_path[FILENAME_MAX]; + int ret, i; + FILE *f; + + ASSERT_EQ(VERSIONS_CNT, CONTROLLERS_CNT); + + ret = mkdir(PARENT_DIR, MODE); + ASSERT_EQ(ret, 0); + + /* + * Artificially populate the mount table with local + * directories + */ + memset(&cg_mount_table, 0, sizeof(cg_mount_table)); + memset(&cg_namespace_table, 0, sizeof(cg_namespace_table)); + + for (i = 0; i < CONTROLLERS_CNT; i++) { + snprintf(cg_mount_table[i].name, FILENAME_MAX, + "%s", CONTROLLERS[i]); + cg_mount_table[i].version = VERSIONS[i]; + + switch (VERSIONS[i]) { + case CGROUP_V1: + snprintf(cg_mount_table[i].mount.path, + FILENAME_MAX, "%s/%s", PARENT_DIR, + CONTROLLERS[i]); + + ret = mkdir(cg_mount_table[i].mount.path, MODE); + ASSERT_EQ(ret, 0); + break; + case CGROUP_V2: + snprintf(cg_mount_table[i].mount.path, + FILENAME_MAX, "%s", PARENT_DIR); + + memset(tmp_path, 0, sizeof(tmp_path)); + snprintf(tmp_path, FILENAME_MAX - 1, + "%s/cgroup.subtree_control", + PARENT_DIR); + + f = fopen(tmp_path, "w"); + ASSERT_NE(f, nullptr); + fclose(f); + break; + default: + /* we shouldn't get here. fail the test */ + ASSERT_TRUE(false); + } + } + } + + /* + * https://stackoverflow.com/questions/5467725/how-to-delete-a-directory-and-its-contents-in-posix-c + */ + static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, + struct FTW *ftwbuf) + { + return remove(fpath); + } + + int rmrf(const char * const path) + { + return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); + } + + void TearDown() override + { + int ret = 0; + + ret = rmrf(PARENT_DIR); + ASSERT_EQ(ret, 0); + } +}; + +static void verify_cgroup_created(const char * const cg_name, + const char * const ctrl) +{ + char tmp_path[FILENAME_MAX]; + DIR *dir; + + memset(tmp_path, 0, sizeof(tmp_path)); + + if (ctrl) + snprintf(tmp_path, FILENAME_MAX - 1, "%s/%s/%s", + PARENT_DIR, ctrl, cg_name); + else + snprintf(tmp_path, FILENAME_MAX - 1, "%s/%s", + PARENT_DIR, cg_name); + + dir = opendir(tmp_path); + ASSERT_NE(dir, nullptr); + closedir(dir); +} + +static void verify_subtree_contents(const char * const expected) +{ + char tmp_path[FILENAME_MAX], buf[4092]; + FILE *f; + + memset(tmp_path, 0, sizeof(tmp_path)); + snprintf(tmp_path, FILENAME_MAX - 1, "%s/cgroup.subtree_control", + PARENT_DIR); + f = fopen(tmp_path, "r"); + ASSERT_NE(f, nullptr); + + while (fgets(buf, sizeof(buf), f)) + ASSERT_STREQ(buf, expected); + fclose(f); +} + +TEST_F(CgroupCreateCgroupTest, CgroupCreateCgroupV1) +{ + struct cgroup_controller *ctrl; + struct cgroup *cg = NULL; + const char * const ctrl_name = "cpu"; + const char * const cg_name = "MyV1Cgroup"; + int ret; + + cg = cgroup_new_cgroup(cg_name); + ASSERT_NE(cg, nullptr); + + ctrl = cgroup_add_controller(cg, ctrl_name); + ASSERT_NE(ctrl, nullptr); + + ret = cgroup_create_cgroup(cg, 1); + ASSERT_EQ(ret, 0); + + verify_cgroup_created(cg_name, ctrl_name); +} + +TEST_F(CgroupCreateCgroupTest, CgroupCreateCgroupV2) +{ + struct cgroup_controller *ctrl; + struct cgroup *cg = NULL; + const char * const ctrl_name = "freezer"; + const char * const cg_name = "MyV2Cgroup"; + int ret; + + cg = cgroup_new_cgroup(cg_name); + ASSERT_NE(cg, nullptr); + + ctrl = cgroup_add_controller(cg, ctrl_name); + ASSERT_NE(ctrl, nullptr); + + ret = cgroup_create_cgroup(cg, 0); + ASSERT_EQ(ret, 0); + + verify_cgroup_created(cg_name, NULL); + verify_subtree_contents("+freezer"); +} + +TEST_F(CgroupCreateCgroupTest, CgroupCreateCgroupV1AndV2) +{ + struct cgroup_controller *ctrl; + struct cgroup *cg = NULL; + const char * const ctrl1_name = "memory"; + const char * const ctrl2_name = "cpuset"; + const char * const cg_name = "MyV1AndV2Cgroup"; + int ret; + + cg = cgroup_new_cgroup(cg_name); + ASSERT_NE(cg, nullptr); + + ctrl = cgroup_add_controller(cg, ctrl1_name); + ASSERT_NE(ctrl, nullptr); + ctrl = NULL; + ctrl = cgroup_add_controller(cg, ctrl2_name); + ASSERT_NE(ctrl, nullptr); + + ret = cgroup_create_cgroup(cg, 1); + ASSERT_EQ(ret, 0); + + verify_cgroup_created(cg_name, NULL); + verify_cgroup_created(cg_name, ctrl2_name); + verify_subtree_contents("+memory"); +} diff --git a/gunit/Makefile.am b/gunit/Makefile.am index bc88985681c6..438bd25b7734 100644 --- a/gunit/Makefile.am +++ b/gunit/Makefile.am @@ -48,6 +48,7 @@ gtest_SOURCES = gtest.cpp \ 008-cgroup_process_v2_mount.cpp \ 009-cgroup_set_values_recursive.cpp \ 010-cgroup_chown_chmod_tasks.cpp \ - 011-cgroupv2_subtree_control.cpp + 011-cgroupv2_subtree_control.cpp \ + 012-cgroup_create_cgroup.cpp gtest_LDFLAGS = -L$(top_builddir)/googletest/googletest -l:libgtest.so \ -rpath $(abs_top_builddir)/googletest/googletest -- 2.25.3 _______________________________________________ Libcg-devel mailing list Libcg-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libcg-devel