summaryrefslogtreecommitdiffstats
path: root/tests/test_functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_functions.c')
-rw-r--r--tests/test_functions.c896
1 files changed, 896 insertions, 0 deletions
diff --git a/tests/test_functions.c b/tests/test_functions.c
new file mode 100644
index 0000000..fc64934
--- /dev/null
+++ b/tests/test_functions.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright IBM Corporation. 2008
+ *
+ * Author: Sudhir Kumar <skumar@linux.vnet.ibm.com>
+ *
+ * This program 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 program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Description: This file contains the functions for testing libcgroup apis.
+ */
+
+#include "libcgrouptest.h"
+
+/* The messages that may be useful to the user */
+char info[][SIZE] = {
+ " Parameter nullcgroup\n", /* NULLGRP */
+ " Parameter commoncgroup\n", /* COMMONGRP */
+ " Parameter not created group\n", /* NOTCRTDGRP */
+ " Parameter same cgroup\n", /* SAMEGRP */
+ " Task found in group/s\n", /* TASKINGRP */
+ " Task not found in group/s\n", /* TASKNOTINGRP */
+ " Task not found in all groups\n", /* TASKNOTINANYGRP */
+ " group found in filesystem\n", /* GRPINFS */
+ " group not found in filesystem\n", /* GRPNOTINFS */
+ " group found under both controllers\n", /* GRPINBOTHCTLS */
+ " group not found under second controller\n", /* GRPNOTIN2NDCTL */
+ " group not found under first controller\n", /* GRPNOTIN1STCTL */
+ " group modified under both controllers\n", /* GRPMODINBOTHCTLS */
+ " group not modified under second controller\n",/* GRPNOTMODIN2NDCTL */
+ " group not modified under any controller\n", /* GRPNOTMODINANYCTL */
+ " Group deleted from filesystem\n", /* GRPDELETEDINFS */
+ " Group not deleted from filesystem\n", /* GRPNOTDELETEDINFS */
+ " Group not deleted globally\n", /* GRPNOTDELETEDGLOBALY */
+ /* In case there is no extra info messages to be printed */
+ "\n", /* NOMESSAGE */
+};
+
+/**
+ * Tests the cgroup_init_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param i the test number
+ */
+void test_cgroup_init(int retcode, int i)
+{
+ int retval;
+
+ retval = cgroup_init();
+ if (retval == retcode)
+ message(i, PASS, "init()\t", retval, info[NOMESSAGE]);
+ else
+ message(i, FAIL, "init()", retval, info[NOMESSAGE]);
+}
+
+/**
+ * Tests the cgroup_attach_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param cgrp the group to assign the task to
+ * @param group1 the name of the group under first (single) mountpoint
+ * @param group2 the name of the group under 2nd moutpoint for multimount
+ * @param i the test number
+ * @param k the message enum number to print the useful message
+ */
+void test_cgroup_attach_task(int retcode, struct cgroup *cgrp,
+ const char *group1, const char *group2, int k, int i)
+{
+ int retval;
+ char tasksfile[FILENAME_MAX], tasksfile2[FILENAME_MAX];
+ /* Check, In case some error is expected due to a negative scenario */
+ if (retcode) {
+ retval = cgroup_attach_task(cgrp);
+ if (retval == retcode)
+ message(i, PASS, "attach_task()", retval, info[k]);
+ else
+ message(i, FAIL, "attach_task()", retval, info[k]);
+
+ return;
+ }
+
+ /* Now there is no error and it is a genuine call */
+ retval = cgroup_attach_task(cgrp);
+ /* API returned success, so perform check */
+ if (retval == 0) {
+ build_path(tasksfile, mountpoint,
+ group1, "tasks");
+
+ if (check_task(tasksfile)) {
+ if (fs_mounted == 2) {
+ /* multiple mounts */
+ build_path(tasksfile2, mountpoint2,
+ group2, "tasks");
+ if (check_task(tasksfile2)) {
+ message(i, PASS, "attach_task()",
+ retval, info[TASKINGRP]);
+ } else {
+ message(i, FAIL, "attach_task()",
+ retval, info[TASKNOTINANYGRP]);
+ }
+ } else {
+ /* single mount */
+ message(i, PASS, "attach_task()",
+ retval, info[TASKINGRP]);
+ }
+ } else {
+ message(i, FAIL, "attach_task()", retval,
+ info[TASKNOTINGRP]);
+ }
+ } else {
+ message(i, FAIL, "attach_task()", retval, (char *)"\n");
+ }
+}
+
+/**
+ * This function creates a cgroup data structure
+ * This function is a bit ugly for now and need to be changed
+ * @param ctl the controller under which group is to be created
+ * @param grpname the name of the group
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ * @param struct ids the permissions struct
+ * @param the test number
+ */
+struct cgroup *create_new_cgroup_ds(int ctl, const char *grpname,
+ int value_type, struct cntl_val_t cval, struct uid_gid_t ids, int i)
+{
+ int retval;
+ char group[FILENAME_MAX];
+ char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+
+ strncpy(group, grpname, sizeof(group));
+ retval = set_controller(ctl, controller_name, control_file);
+ if (retval) {
+ fprintf(stderr, "Setting controller failled\n");
+ return NULL;
+ }
+
+ switch (ctl) {
+ /* control values are controller specific, so will be set
+ * accordingly from the config file */
+ case CPU:
+ strncpy(cval.val_string, "260000", sizeof(cval.val_string));
+ break;
+
+ case MEMORY:
+ strncpy(cval.val_string, "7000064", sizeof(cval.val_string));
+ break;
+
+ /* To be added for other controllers */
+ default:
+ printf("Invalid controller name passed. Setting control value"
+ " failed. Dependent tests may fail\n");
+ return NULL;
+ break;
+ }
+
+ return new_cgroup(group, controller_name, control_file,
+ value_type, cval, ids, i);
+}
+
+/**
+ * Tests the cgroup_create_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param cgrp the group to be created
+ * @param name the name of the group
+ * @param common to test if group will be created under one or both mountpoints
+ * @param mpnt to test if group under mountpoint or mountpoint2
+ * @param ign parameter for api if to ignore the ownership
+ * @param the test number
+ */
+void test_cgroup_create_cgroup(int retcode, struct cgroup *cgrp,
+ const char *name, int common, int mpnt, int ign, int i)
+{
+ int retval;
+ char path1_group[FILENAME_MAX], path2_group[FILENAME_MAX];
+ /* Check, In case some error is expected due to a negative scenario */
+ if (retcode) {
+ retval = cgroup_create_cgroup(cgrp, ign);
+ if (retval == retcode)
+ message(i, PASS, "create_cgroup()", retval,
+ info[NOMESSAGE]);
+ else
+ message(i, FAIL, "create_cgroup()", retval,
+ info[NOMESSAGE]);
+
+ return;
+ }
+
+ /* Now there is no error and it is a genuine call */
+ retval = cgroup_create_cgroup(cgrp, ign);
+ if (retval) {
+ message(i, FAIL, "create_cgroup()", retval, info[NOMESSAGE]);
+ return;
+ }
+
+ /* Let us now check if the group exist in file system */
+ if (!common) {
+ /* group only under one mountpoint */
+ if (mpnt == 1)
+ /* group under mountpoint */
+ build_path(path1_group, mountpoint, name, NULL);
+ else
+ /* group under mountpoint2 */
+ build_path(path1_group, mountpoint2, name, NULL);
+
+ if (group_exist(path1_group) == 0)
+ message(i, PASS, "create_cgroup()", retval,
+ info[GRPINFS]);
+ else
+ message(i, FAIL, "create_cgroup()", retval,
+ info[GRPNOTINFS]);
+
+ /* group under both mountpoints */
+ } else {
+ /* check if the group exists under both controllers */
+ build_path(path1_group, mountpoint, name, NULL);
+ if (group_exist(path1_group) == 0) {
+ build_path(path2_group, mountpoint2, name, NULL);
+
+ if (group_exist(path2_group) == 0)
+ message(i, PASS, "create_cgroup()",
+ retval, info[GRPINBOTHCTLS]);
+ else
+ message(i, FAIL, "create_cgroup()",
+ retval, info[GRPNOTIN2NDCTL]);
+ } else {
+ message(i, FAIL, "create_cgroup()", retval,
+ info[GRPNOTIN1STCTL]);
+ }
+ }
+
+ return;
+}
+
+/**
+ * Tests the cgroup_delete_cgroup() api under different scenarios
+ * @param retcode error code in case any error is expected from api
+ * @param cgrp the group to be deleted
+ * @param name the name of the group
+ * @param common to test if group was created under one or both mountpoints
+ * @param mpnt to test if group under mountpoint or mountpoint2
+ * @param ign parameter for api if to ignore the ownership
+ * @param the test number
+ */
+void test_cgroup_delete_cgroup(int retcode, struct cgroup *cgrp,
+ const char *name, int common, int mpnt, int ign, int i)
+{
+ int retval;
+ char path1_group[FILENAME_MAX], path2_group[FILENAME_MAX];
+ /* Check, In case some error is expected due to a negative scenario */
+ if (retcode) {
+ retval = cgroup_delete_cgroup(cgrp, ign);
+ if (retval == retcode)
+ message(i, PASS, "delete_cgroup()", retval,
+ info[NOMESSAGE]);
+ else
+ message(i, FAIL, "delete_cgroup()", retval,
+ info[NOMESSAGE]);
+
+ return;
+ }
+
+ /* Now there is no error and it is a genuine call */
+ retval = cgroup_delete_cgroup(cgrp, ign);
+ if (retval) {
+ message(i, FAIL, "delete_cgroup()", retval, info[NOMESSAGE]);
+ return;
+ }
+
+ /* Let us now check if the group has been deleted from file system */
+ if (!common) {
+ /* check only under one mountpoint */
+ if (mpnt == 1)
+ /* check group under mountpoint */
+ build_path(path1_group, mountpoint, name, NULL);
+ else
+ /* check group under mountpoint2 */
+ build_path(path1_group, mountpoint2, name, NULL);
+
+ if (group_exist(path1_group) == -1)
+ message(i, PASS, "delete_cgroup()", retval,
+ info[GRPDELETEDINFS]);
+ else
+ message(i, FAIL, "delete_cgroup()", retval,
+ info[GRPNOTDELETEDINFS]);
+
+ } else {
+ /* check group under both mountpoints */
+ /* Check if the group deleted under both mountpoints */
+ build_path(path1_group, mountpoint, name, NULL);
+ if (group_exist(path1_group) == -1) {
+ build_path(path2_group, mountpoint2, name, NULL);
+
+ if (group_exist(path2_group) == -1)
+ message(i, PASS, "delete_cgroup()",
+ retval, info[GRPDELETEDINFS]);
+ else
+ message(i, FAIL, "delete_cgroup()",
+ retval, info[GRPNOTDELETEDGLOBALY]);
+ } else {
+ message(i, FAIL, "delete_cgroup()", retval,
+ info[GRPNOTDELETEDINFS]);
+ }
+ }
+
+}
+
+/**
+ * The function tests if the given controller is enabled in kernel
+ * @param name the name of the controller to be checked
+ * @param exist set to 1 if the controller exists
+ */
+void get_controllers(const char *name, int *exist)
+{
+ int hierarchy, num_cgroups, enabled;
+ FILE *fd;
+ char subsys_name[FILENAME_MAX];
+
+ fd = fopen("/proc/cgroups", "r");
+ if (!fd)
+ return;
+
+ while (!feof(fd)) {
+ fscanf(fd, "%s, %d, %d, %d", subsys_name,
+ &hierarchy, &num_cgroups, &enabled);
+ if (strncmp(name, subsys_name, sizeof(*name)) == 0)
+ *exist = 1;
+ }
+
+ fclose(fd);
+}
+
+/**
+ * This function tests if the given group exists in filesystem
+ * @param path_group path to the group to be tested for existence
+ */
+int group_exist(char *path_group)
+{
+ int ret;
+ ret = open(path_group, O_DIRECTORY);
+ if (ret == -1)
+ return ret;
+ return 0;
+}
+
+/**
+ * Sets the controller name and control file name
+ * @param controller the enum for the name of the controller
+ * @param controller_name name of the controller
+ * @param control_file corresponding control file
+ */
+int set_controller(int controller, char *controller_name, char *control_file)
+{
+ switch (controller) {
+ case MEMORY:
+ if (memory == 0)
+ return 1;
+
+ strncpy(controller_name, "memory", FILENAME_MAX);
+ strncpy(control_file, "memory.limit_in_bytes", FILENAME_MAX);
+ return 0;
+ break;
+
+ case CPU:
+ if (cpu == 0)
+ return 1;
+
+ strncpy(controller_name, "cpu", FILENAME_MAX);
+ strncpy(control_file, "cpu.shares", FILENAME_MAX);
+ return 0;
+ break;
+
+ case CPUSET:
+ strncpy(controller_name, "cpuset", FILENAME_MAX);
+ strncpy(control_file, "cpuset.cpus", FILENAME_MAX);
+ return 0;
+ break;
+ /* Future controllers can be added here */
+
+ default:
+ printf("Invalid controller name passed. Setting controller"
+ " failed. Dependent tests may fail\n");
+ return 1;
+ break;
+ }
+}
+
+/**
+ * Tests if a group has been modified
+ * @param path_control_file path to the control file of the controller
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ */
+int group_modified(char *path_control_file, int value_type,
+ struct cntl_val_t cval)
+{
+ bool bool_val;
+ int64_t int64_val;
+ u_int64_t uint64_val;
+ /* 100 char looks ok for a control value as string */
+ char string_val[100];
+ FILE *fd;
+ int error = 1;
+
+ fd = fopen(path_control_file, "r");
+ if (!fd) {
+ fprintf(stderr, "Error in opening %s\n", path_control_file);
+ fprintf(stderr, "Skipping modified values check....\n");
+ return 1;
+ }
+
+ switch (value_type) {
+
+ case BOOL:
+ fscanf(fd, "%d", &bool_val);
+ if (bool_val == cval.val_bool)
+ error = 0;
+ break;
+ case INT64:
+ fscanf(fd, "%lld", &int64_val);
+ if (int64_val == cval.val_int64)
+ error = 0;
+ break;
+ case UINT64:
+ fscanf(fd, "%llu", &uint64_val);
+ if (uint64_val == cval.val_uint64)
+ error = 0;
+ break;
+ case STRING:
+ fscanf(fd, "%s", string_val);
+ if (!strncmp(string_val, cval.val_string, strlen(string_val)))
+ error = 0;
+ break;
+ default:
+ fprintf(stderr, "Wrong value_type passed "
+ "in group_modified()\n");
+ fprintf(stderr, "Skipping modified values check....\n");
+ /* Can not report test result as failure */
+ error = 0;
+ break;
+ }
+
+ fclose(fd);
+ return error;
+}
+
+/**
+ * Adds the control value to a controller using wrapper apis
+ * @param newcontroller the controller to be added the value to
+ * @param control_file name of the control file of the controller
+ * @param wr the name of wrapper api
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ */
+int add_control_value(struct cgroup_controller *newcontroller,
+ char *control_file, char *wr, int value_type, struct cntl_val_t cval)
+{
+ int retval;
+
+ switch (value_type) {
+
+ case BOOL:
+ retval = cgroup_add_value_bool(newcontroller,
+ control_file, cval.val_bool);
+ snprintf(wr, SIZE, "add_value_bool()");
+ break;
+ case INT64:
+ retval = cgroup_add_value_int64(newcontroller,
+ control_file, cval.val_int64);
+ snprintf(wr, SIZE, "add_value_int64()");
+ break;
+ case UINT64:
+ retval = cgroup_add_value_uint64(newcontroller,
+ control_file, cval.val_uint64);
+ snprintf(wr, SIZE, "add_value_uint64()");
+ break;
+ case STRING:
+ retval = cgroup_add_value_string(newcontroller,
+ control_file, cval.val_string);
+ snprintf(wr, SIZE, "add_value_string()");
+ break;
+ default:
+ printf("ERROR: wrong value in add_control_value()\n");
+ return 1;
+ break;
+ }
+ return retval;
+}
+
+/**
+ * This function creates and returns a cgroup data structure
+ * @param group the name of the group
+ * @param controller_name the name of the controller to be added to the group
+ * @param control_file name of the control file of the controller
+ * @param value_type which value out of four types
+ * @param struct cval the control value structure
+ * @param struct ids the permissions struct
+ * @param the test number
+ */
+struct cgroup *new_cgroup(char *group, char *controller_name,
+ char *control_file, int value_type,
+ struct cntl_val_t cval, struct uid_gid_t ids, int i)
+{
+ int retval;
+ /* Names of wrapper apis */
+ char wr[SIZE];
+ struct cgroup *newcgroup;
+ struct cgroup_controller *newcontroller;
+
+ newcgroup = cgroup_new_cgroup(group);
+
+ if (newcgroup) {
+ retval = cgroup_set_uid_gid(newcgroup, ids.tasks_uid,
+ ids.tasks_gid, ids.control_uid, ids.control_gid);
+
+ if (retval) {
+ snprintf(wr, SIZE, "set_uid_gid()");
+ message(i++, FAIL, wr, retval, info[NOMESSAGE]);
+ }
+
+ newcontroller = cgroup_add_controller(newcgroup,
+ controller_name);
+ if (newcontroller) {
+ retval = add_control_value(newcontroller,
+ control_file, wr, value_type, cval);
+
+ if (!retval) {
+ message(i++, PASS, "new_cgroup()",
+ retval, info[NOMESSAGE]);
+ } else {
+ message(i++, FAIL, wr, retval ,
+ info[NOMESSAGE]);
+ return NULL;
+ }
+ } else {
+ /* Since these wrappers do not return an int so -1 */
+ message(i++, FAIL, "add_controller", -1,
+ info[NOMESSAGE]);
+ return NULL;
+ }
+ } else {
+ message(i++, FAIL, "new_cgroup", -1, info[NOMESSAGE]);
+ return NULL;
+ }
+ return newcgroup;
+}
+
+/**
+ * Checks if the cgroup filesystem has been mounted
+ * @param multimnt to decide if check is for single mount or multimount
+ */
+int check_fsmounted(int multimnt)
+{
+ int count = 0;
+ int ret = 1;
+ struct mntent *entry = NULL, *tmp_entry = NULL;
+ /* Need a better mechanism to decide memory allocation size here */
+ char entry_buffer[FILENAME_MAX * 4];
+ FILE *proc_file = NULL;
+
+ tmp_entry = (struct mntent *) malloc(sizeof(struct mntent));
+ if (!tmp_entry) {
+ perror("Error: failled to mallloc for mntent\n");
+ ret = errno;
+ goto error;
+ }
+
+ proc_file = fopen("/proc/mounts", "r");
+ if (!proc_file) {
+ printf("Error in opening /proc/mounts.\n");
+ ret = errno;
+ goto error;
+ }
+ while ((entry = getmntent_r(proc_file, tmp_entry, entry_buffer,
+ FILENAME_MAX*4)) != NULL) {
+ if (!strncmp(entry->mnt_type, "cgroup", strlen("cgroup"))) {
+ count++;
+ if (multimnt) {
+ if (count >= 2) {
+ printf("sanity check pass. %s\n",
+ entry->mnt_type);
+ ret = 0;
+ goto error;
+ }
+ } else {
+ printf("sanity check pass. %s\n",
+ entry->mnt_type);
+ ret = 0;
+ goto error;
+ }
+ }
+ }
+error:
+ if (tmp_entry)
+ free(tmp_entry);
+ if (proc_file)
+ fclose(proc_file);
+ return ret;
+}
+
+/**
+ * Checks if the current task belongs to the given tasks file
+ * @param tasksfile the task file to be tested for the task
+ */
+int check_task(char *tasksfile)
+{
+ FILE *file;
+ pid_t curr_tid, tid;
+ int pass = 0;
+
+ file = fopen(tasksfile, "r");
+ if (!file) {
+ printf("ERROR: in opening %s\n", tasksfile);
+ printf("Exiting without running other testcases in this set\n");
+ exit(1);
+ }
+
+ curr_tid = cgrouptest_gettid();
+ while (!feof(file)) {
+ fscanf(file, "%u", &tid);
+ if (tid == curr_tid) {
+ pass = 1;
+ break;
+ }
+ }
+ fclose(file);
+
+ return pass;
+}
+
+/**
+ * Prints the test result in a readable format with some verbose messages
+ * @param num the test number
+ * @param pass test passed or failed
+ * @param api the name of the api tested
+ * @param retval the return value of the api
+ * @param extra the extra message to the user about the scenario tested
+ */
+void message(int num, int pass, const char *api, int retval, char *extra)
+{
+ char res[10];
+ char buf[2*SIZE];
+ if (pass)
+ strncpy(res, "PASS :", 10);
+ else
+ strncpy(res, "FAIL :", 10);
+
+ /* Populate message buffer for the api */
+ snprintf(buf, sizeof(buf), "cgroup_%s\t\t Ret Value = ", api);
+ fprintf(stdout, "TEST%2d:%s %s%d\t%s", num, res, buf, retval, extra);
+}
+
+/**
+ * Builds the path to target file/group
+ * @param target to write the built path to
+ * @param mountpoint for which mountpoint the path to be built
+ * @param group the name of the group (directory)
+ * @param file what file under the group
+ */
+void
+build_path(char *target, char *mountpoint, const char *group, const char *file)
+{
+ if (!target)
+ return;
+
+ strncpy(target, mountpoint, FILENAME_MAX);
+
+ if (group) {
+ strncat(target, "/", FILENAME_MAX - strlen(target));
+ strncat(target, group, FILENAME_MAX - strlen(target));
+ }
+
+ if (file) {
+ strncat(target, "/", FILENAME_MAX - strlen(target));
+ strncat(target, file, FILENAME_MAX - strlen(target));
+ }
+}
+
+/**
+ * Tests the cgroup_compare_cgroup() api under different scenarios
+ * @param ctl1 controller 1 to be used for testing
+ * @param ctl2 controller 1 to be used for testing
+ * @param the test number
+ */
+void test_cgroup_compare_cgroup(int ctl1, int ctl2, int i)
+{
+ int retval;
+
+ struct cntl_val_t cval;
+ cval.val_int64 = 0;
+ cval.val_uint64 = 0;
+ cval.val_bool = 0;
+ strcpy(cval.val_string, "5000");
+
+ struct cgroup *cgroup1 = NULL, *cgroup2 = NULL;
+ struct cgroup_controller *controller = NULL;
+ char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+ char wr[SIZE], extra[] = "in cgroup_compare_cgroup";
+
+ retval = cgroup_compare_cgroup(NULL, NULL);
+ if (retval)
+ message(i++, PASS, "compare_cgroup()", retval, info[NULLGRP]);
+ else
+ message(i++, FAIL, "compare_cgroup()", retval, info[NULLGRP]);
+
+ cgroup1 = cgroup_new_cgroup("testgroup");
+ cgroup2 = cgroup_new_cgroup("testgroup");
+ cgroup_set_uid_gid(cgroup1, 0, 0, 0, 0);
+ cgroup_set_uid_gid(cgroup2, 0, 0, 0, 0);
+
+ retval = set_controller(ctl1, controller_name, control_file);
+
+ controller = cgroup_add_controller(cgroup1, controller_name);
+ if (controller) {
+ retval = add_control_value(controller,
+ control_file, wr, STRING, cval);
+ if (retval)
+ message(i++, FAIL, wr, retval, extra);
+ }
+
+ controller = cgroup_add_controller(cgroup2, controller_name);
+ if (controller) {
+ retval = add_control_value(controller,
+ control_file, wr, STRING, cval);
+ if (retval)
+ message(i++, FAIL, wr, retval, extra);
+ }
+
+ retval = cgroup_compare_cgroup(cgroup1, cgroup2);
+ if (retval)
+ message(i++, FAIL, "compare_cgroup()", retval, info[NOMESSAGE]);
+ else
+ message(i++, PASS, "compare_cgroup()", retval, info[NOMESSAGE]);
+
+ /* Test the api by putting diff number of controllers in cgroups */
+ retval = set_controller(ctl2, controller_name, control_file);
+ controller = cgroup_add_controller(cgroup2, controller_name);
+ if (controller) {
+ retval = add_control_value(controller,
+ control_file, wr, STRING, cval);
+ if (retval)
+ message(i++, FAIL, wr, retval, extra);
+ }
+
+ retval = cgroup_compare_cgroup(cgroup1, cgroup2);
+ if (retval == ECGROUPNOTEQUAL)
+ message(i++, PASS, "compare_cgroup()", retval, info[NOMESSAGE]);
+ else
+ message(i++, FAIL, "compare_cgroup()", retval, info[NOMESSAGE]);
+
+ cgroup_free(&cgroup1);
+ cgroup_free(&cgroup2);
+}
+
+/**
+ * Tests the cgroup_get_cgroup() api under different scenarios
+ * @param ctl1 controller 1 to be used for testing
+ * @param ctl2 controller 1 to be used for testing
+ * @param struct ids the permissions struct
+ * @param the test number
+ */
+void test_cgroup_get_cgroup(int ctl1, int ctl2, struct uid_gid_t ids, int i)
+{
+ struct cgroup *cgroup_filled = NULL, *cgroup_a = NULL, *cgroup_b = NULL;
+ struct cgroup_controller *controller = NULL;
+ char controller_name[FILENAME_MAX], control_file[FILENAME_MAX];
+ struct cntl_val_t cval = {0, 0, 0, "5000"};
+ int ret;
+
+ /*
+ * No need to test the next 3 scenarios separately for Multimnt
+ * so testing them only under single mount
+ */
+ if (fs_mounted == FS_MOUNTED) {
+ /* 1. Test with nullcgroup first */
+ ret = cgroup_get_cgroup(NULL);
+ if (ret == ECGROUPNOTALLOWED)
+ message(i++, PASS, "get_cgroup()", ret, info[NULLGRP]);
+ else
+ message(i++, FAIL, "get_cgroup()", ret, info[NULLGRP]);
+
+ /* 2. Test with invalid name filled cgroup(non existing) */
+ cgroup_filled = cgroup_new_cgroup("nogroup");
+ if (!cgroup_filled)
+ message(i++, FAIL, "new_cgroup()", 0, info[NOMESSAGE]);
+
+ ret = cgroup_get_cgroup(cgroup_filled);
+ if (ret)
+ message(i++, PASS, "get_cgroup()", ret,
+ info[NOTCRTDGRP]);
+ else
+ message(i++, FAIL, "get_cgroup()", ret,
+ info[NOTCRTDGRP]);
+ /* Free the allocated cgroup before reallocation */
+ cgroup_free(&cgroup_filled);
+
+ /* 3.
+ * Test with name filled cgroup. Ensure the group group1 exists
+ * in the filesystem before calling this test function
+ */
+ cgroup_filled = cgroup_new_cgroup("group1");
+ if (!cgroup_filled)
+ message(i++, FAIL, "new_cgroup()", 0, info[NOMESSAGE]);
+
+ ret = cgroup_get_cgroup(cgroup_filled);
+ if (!ret)
+ message(i++, PASS, "get_cgroup()", ret,
+ info[NOMESSAGE]);
+ else
+ message(i++, FAIL, "get_cgroup()", ret,
+ info[NOMESSAGE]);
+ }
+
+ /* SINGLE & MULTI MOUNT: Create, get and compare a cgroup */
+
+ /* get cgroup_a ds and create group_a in filesystem */
+ cgroup_a = create_new_cgroup_ds(ctl1, "group_a", STRING, cval, ids, 0);
+ if (fs_mounted == FS_MULTI_MOUNTED) {
+ /* Create under another controller also */
+ ret = set_controller(ctl2, controller_name, control_file);
+ controller = cgroup_add_controller(cgroup_a, controller_name);
+ }
+ test_cgroup_create_cgroup(0, cgroup_a, "group_a", 0, 1, 1, 00);
+
+ /* create group_b ds to be filled by cgroup_get_cgroup */
+ cgroup_b = cgroup_new_cgroup("group_a");
+ if (!cgroup_b)
+ message(i++, FAIL, "new_cgroup()", 0, info[NOMESSAGE]);
+ /* Fill the ds and compare the two */
+ ret = cgroup_get_cgroup(cgroup_b);
+ if (!ret) {
+ ret = cgroup_compare_cgroup(cgroup_a, cgroup_b);
+ if (ret == 0)
+ message(i++, PASS, "get_cgroup()", ret, info[SAMEGRP]);
+ else
+ message(i++, FAIL, "get_cgroup()", ret,
+ info[NOMESSAGE]);
+ } else {
+ message(i++, FAIL, "get_cgroup()", ret, info[NOMESSAGE]);
+ }
+
+ /* Delete this created group from fs to leave fs clean */
+ if (fs_mounted == FS_MULTI_MOUNTED)
+ test_cgroup_delete_cgroup(0, cgroup_a, "group_a", 1, 1, 0, 0);
+ else
+ test_cgroup_delete_cgroup(0, cgroup_a, "group_a", 0, 1, 0, 0);
+
+ cgroup_free(&cgroup_a);
+ cgroup_free(&cgroup_b);
+ cgroup_free(&cgroup_filled);
+}
+
+/**
+ * Tests the cgroup_add_controller() and cgroup_free_controller() wrapper
+ * apis under different scenarios
+ * @param the test number
+ */
+void test_cgroup_add_free_controller(int i)
+{
+ struct cgroup *cgroup1 = NULL, *cgroup2 = NULL;
+ struct cgroup_controller *cgctl1, *cgctl2;
+
+ /* Test with a Null cgroup */
+ cgctl1 = cgroup_add_controller(cgroup1, "cpu");
+ if (!cgctl1)
+ message(i++, PASS, "add_controller()", 0, info[NOMESSAGE]);
+ else
+ message(i++, FAIL, "add_controller()", -1, info[NOMESSAGE]);
+
+ cgroup1 = cgroup_new_cgroup("testgroup");
+ cgctl1 = cgroup_add_controller(cgroup1, "cpuset");
+ if (cgctl1)
+ message(i++, PASS, "add_controller()", 0, info[NOMESSAGE]);
+ else
+ message(i++, FAIL, "add_controller()", -1, info[NOMESSAGE]);
+
+ cgctl2 = cgroup_add_controller(cgroup1, "cpu");
+ if (cgctl2)
+ message(i++, PASS, "add_controller()", 0, info[NOMESSAGE]);
+ else
+ message(i++, FAIL, "add_controller()", -1, info[NOMESSAGE]);
+
+ cgroup_free(&cgroup1);
+ cgroup_free_controllers(cgroup2);
+}
+
+/**
+ * Returns the tid of the current thread
+ */
+pid_t cgrouptest_gettid()
+{
+ return syscall(__NR_gettid);
+}