This commit adds a unit test for cgroup_get_cgroup().  To
facilitate this, it creates a pseudo-cgroup sysfs in the
working directory and updates the test's cg_mount_table[]
to point at this temporary directory.

[----------] 2 tests from CgroupGetCgroupTest
[ RUN      ] CgroupGetCgroupTest.CgroupGetCgroup1
[       OK ] CgroupGetCgroupTest.CgroupGetCgroup1 (3 ms)
[ RUN      ] CgroupGetCgroupTest.CgroupGetCgroup_NoTasksFile
[       OK ] CgroupGetCgroupTest.CgroupGetCgroup_NoTasksFile (2 ms)
[----------] 2 tests from CgroupGetCgroupTest (6 ms total)

Signed-off-by: Tom Hromatka <tom.hroma...@oracle.com>
---
 tests/gunit/006-cgroup_get_cgroup.cpp | 268 ++++++++++++++++++++++++++
 tests/gunit/Makefile.am               |   3 +-
 2 files changed, 270 insertions(+), 1 deletion(-)
 create mode 100644 tests/gunit/006-cgroup_get_cgroup.cpp

diff --git a/tests/gunit/006-cgroup_get_cgroup.cpp 
b/tests/gunit/006-cgroup_get_cgroup.cpp
new file mode 100644
index 000000000000..e3f5b1e68adb
--- /dev/null
+++ b/tests/gunit/006-cgroup_get_cgroup.cpp
@@ -0,0 +1,268 @@
+/**
+ * libcgroup googletest for cgroup_get_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 <bits/stdc++.h>
+#include <string>
+#include <vector>
+using namespace std;
+
+#include <ftw.h>
+
+#include "gtest/gtest.h"
+#include "libcgroup-internal.h"
+
+#define MAX_NAMES 5
+
+enum ctrl_enum {
+       CTRL_CPU,
+       CTRL_FREEZER,
+       CTRL_MEMORY,
+       CTRL_CPUSET,
+       CTRL_NAMESPACES,
+       CTRL_NETNS,
+
+       CTRL_CNT
+};
+
+static const char * const PARENT_DIR = "test006cgroup";
+
+static const char * const CONTROLLERS[] = {
+       "cpu",
+       "freezer",
+       "memory",
+       "cpuset",
+       "namespaces",
+       "netns",
+};
+static const int CONTROLLERS_CNT =
+       sizeof(CONTROLLERS) / sizeof(CONTROLLERS[0]);
+
+static const char * const NAMES[][MAX_NAMES] = {
+       {"tasks", "cpu.shares", "cpu.weight", "cpu.foo", NULL},
+       {"tasks", NULL, NULL, NULL, NULL},
+       {"tasks", "memory.limit_in_bytes", "memory.memsw.limit_in_bytes", NULL, 
NULL},
+       {"tasks", "cpuset.exclusive", "cpuset.foo", "cpuset.bar", "cpuset.x"},
+       {"tasks", "namespaces.blah", NULL, NULL, NULL},
+       {"tasks", "netns.foo", "netns.bar", "netns.baz", NULL},
+};
+static const int NAMES_CNT = sizeof(NAMES) / sizeof(NAMES[0]);
+
+static const char * const VALUES[][MAX_NAMES] = {
+       {"1234", "512", "100", "abc123", NULL},
+       {"2345\n3456", NULL, NULL, NULL, NULL},
+       {"456\n678\n890", "8675309", "1024000", NULL, NULL},
+       {"\0", "1", "limit=32412039", "9223372036854771712", "partition"},
+       {"59832", "The Quick Brown Fox", NULL, NULL, NULL},
+       {"987\n654", "root", "/sys/fs", "0xdeadbeef", NULL},
+};
+static const int VALUES_CNT = sizeof(VALUES) / sizeof(VALUES[0]);
+
+static const char * const CG_NAME = "tomcatcg";
+static const mode_t MODE = S_IRWXU | S_IRWXG | S_IRWXO;
+
+class CgroupGetCgroupTest : public ::testing::Test {
+       protected:
+
+       void CreateNames(const char * const names[],
+                        const char * const values[],
+                        const char * const ctrl_name) {
+               char tmp_path[FILENAME_MAX];
+               FILE *f;
+               int i;
+
+               for (i = 0; i < NAMES_CNT; i++) {
+                       if (names[i] == NULL)
+                               break;
+
+                       memset(tmp_path, 0, sizeof(tmp_path));
+                       snprintf(tmp_path, FILENAME_MAX - 1, "%s/%s/%s/%s",
+                                PARENT_DIR, ctrl_name, CG_NAME, names[i]);
+
+                       f = fopen(tmp_path, "w");
+                       ASSERT_NE(f, nullptr);
+
+                       fprintf(f, "%s", values[i]);
+                       fclose(f);
+               }
+       }
+
+       void SetUp() override {
+               char tmp_path[FILENAME_MAX];
+               int i, j, names_len, ret;
+
+               ASSERT_EQ(NAMES_CNT, CONTROLLERS_CNT);
+               ASSERT_EQ(NAMES_CNT, VALUES_CNT);
+
+               ret = cgroup_init();
+               ASSERT_EQ(ret, 0);
+
+               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]);
+                       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);
+
+                       /*
+                        * arbitrarily don't make the cgroup directory in
+                        * the freezer controller
+                        */
+                       if (i == CTRL_FREEZER)
+                               continue;
+
+                       memset(tmp_path, 0, sizeof(tmp_path));
+                       snprintf(tmp_path, FILENAME_MAX - 1, "%s/%s/%s",
+                                PARENT_DIR, CONTROLLERS[i], CG_NAME);
+                       ret = mkdir(tmp_path, MODE);
+                       ASSERT_EQ(ret, 0);
+
+                       CreateNames(NAMES[i], VALUES[i], CONTROLLERS[i]);
+               }
+       }
+
+       /*
+        * 
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 vectorize_cg(const struct cgroup * const cg,
+                        vector<string>& cg_vec)
+{
+       const char *cgname, *cgcname, *value;
+       int i, j;
+
+       for (i = 0; i < cg->index; i++) {
+               for (j = 0; j < cg->controller[i]->index; j++) {
+                       string cgname(cg->name);
+                       string cgcname(cg->controller[i]->name);
+                       string name(cg->controller[i]->values[j]->name);
+                       string value(cg->controller[i]->values[j]->value);
+
+                       cg_vec.push_back(cgcname + "+" + cgname + "+" +
+                                        name + "+" + value);
+               }
+       }
+
+       sort(cg_vec.begin(), cg_vec.end());
+}
+
+static void vectorize_testdata(vector<string>& test_vec)
+{
+       string cgname(CG_NAME);
+       int i, j;
+
+       for (i = 0; i < CTRL_CNT; i++) {
+               for (j = 0; j < MAX_NAMES; j++) {
+                       if (NAMES[i][j] == NULL)
+                               continue;
+
+                       if (strcmp(NAMES[i][j], "tasks") == 0)
+                               /*
+                                * The tasks files isn't listed by
+                                * cgroup_get_cgroup()
+                                */
+                               continue;
+
+                       string cgcname(CONTROLLERS[i]);
+                       string name(NAMES[i][j]);
+                       string value(VALUES[i][j]);
+
+                       test_vec.push_back(cgcname + "+" + cgname + "+" +
+                                          name + "+" + value);
+               }
+       }
+
+       sort(test_vec.begin(), test_vec.end());
+}
+
+TEST_F(CgroupGetCgroupTest, CgroupGetCgroup1)
+{
+       vector<string> cg_vec, test_vec;
+       struct cgroup *cg = NULL;
+       int ret;
+
+       cg = cgroup_new_cgroup(CG_NAME);
+       ASSERT_NE(cg, nullptr);
+
+       ret = cgroup_get_cgroup(cg);
+       ASSERT_EQ(ret, 0);
+
+       vectorize_cg(cg, cg_vec);
+       vectorize_testdata(test_vec);
+
+       ASSERT_EQ(cg_vec, test_vec);
+
+       if (cg)
+               free(cg);
+}
+
+/*
+ * This test must be last because it makes destructive changes to the cgroup 
hierarchy
+ */
+TEST_F(CgroupGetCgroupTest, CgroupGetCgroup_NoTasksFile)
+{
+       char tmp_path[FILENAME_MAX];
+       struct cgroup *cg = NULL;
+       int ret;
+
+       snprintf(tmp_path, FILENAME_MAX - 1, "%s/%s/%s/tasks",
+                PARENT_DIR, CONTROLLERS[CONTROLLERS_CNT - 1], CG_NAME);
+       ret = rmrf(tmp_path);
+       ASSERT_EQ(ret, 0);
+
+       cg = cgroup_new_cgroup(CG_NAME);
+       ASSERT_NE(cg, nullptr);
+
+       ret = cgroup_get_cgroup(cg);
+       ASSERT_EQ(ret, ECGOTHER);
+
+       if (cg)
+               free(cg);
+}
diff --git a/tests/gunit/Makefile.am b/tests/gunit/Makefile.am
index c6d2e42781c8..c06e04295cc1 100644
--- a/tests/gunit/Makefile.am
+++ b/tests/gunit/Makefile.am
@@ -41,6 +41,7 @@ gtest_SOURCES = gtest.cpp \
                002-cgroup_parse_rules_options.cpp \
                003-cg_get_cgroups_from_proc_cgroups.cpp \
                004-cgroup_compare_ignore_rule.cpp \
-               005-cgroup_compare_wildcard_procname.cpp
+               005-cgroup_compare_wildcard_procname.cpp \
+               006-cgroup_get_cgroup.cpp
 gtest_LDFLAGS = -L$(top_builddir)/googletest/googletest -l:libgtest.so \
                -rpath $(abs_top_builddir)/googletest/googletest
-- 
2.21.0



_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to