From: Starzyk, MateuszX Date: Wed, 21 Mar 2018 08:14:53 +0000 (+0000) Subject: intel_rdt: update unit-tests for process monitoring X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=7f6e8b79ab4bf40d08c8955e1feb67416f2dc358;p=collectd.git intel_rdt: update unit-tests for process monitoring Refactor certain functions to be testable. Change-Id: I5adb6ed1b076f0cebc70641f04dd101d4e89b9cc Signed-off-by: Starzyk, MateuszX --- diff --git a/src/intel_rdt.c b/src/intel_rdt.c index f7d9a341..e509b875 100644 --- a/src/intel_rdt.c +++ b/src/intel_rdt.c @@ -144,6 +144,14 @@ static int strlisttoarray(char *str_list, char ***names, size_t *names_num) { if (str_list == NULL || names == NULL) return -EINVAL; + if (strstr(str_list, ",,")) { + /* strtok ignores empty words between separators. + * This condition handles that by rejecting strings + * with consecutive seprators */ + ERROR(RDT_PLUGIN ": Empty process name"); + return -EINVAL; + } + for (;;) { char *token = strtok_r(str_list, ",", &saveptr); if (token == NULL) @@ -157,11 +165,16 @@ static int strlisttoarray(char *str_list, char ***names, size_t *names_num) { if (*token == '\0') continue; - if (!(isdupstr((const char **)*names, *names_num, token))) + if ((isdupstr((const char **)*names, *names_num, token))) { + ERROR(RDT_PLUGIN ": Duplicated process name \'%s\' in group \'%s\'", + token, str_list); + return -EINVAL; + } else { if (0 != strarray_add(names, names_num, token)) { ERROR(RDT_PLUGIN ": Error allocating process name string"); return -ENOMEM; } + } } return 0; @@ -242,8 +255,10 @@ static int oconfig_to_ngroups(const oconfig_item_t *item, char value[DATA_MAX_NAME_LEN]; if ((item->values[j].value.string == NULL) || - (strlen(item->values[j].value.string) == 0)) - continue; + (strlen(item->values[j].value.string) == 0)) { + ERROR(RDT_PLUGIN ": Error - empty group"); + return -EINVAL; + } sstrncpy(value, item->values[j].value.string, sizeof(value)); @@ -440,26 +455,27 @@ static int pids_list_free(pids_list_t *list) { return 0; } -static void rdt_free_ngroups(void) { +static void rdt_free_ngroups(rdt_ctx_t *rdt) { for (int i = 0; i < RDT_MAX_NAMES_GROUPS; i++) { - if (g_rdt->ngroups[i].desc) + if (rdt->ngroups[i].desc) DEBUG(RDT_PLUGIN ": Freeing pids \'%s\' group\'s data...", - g_rdt->ngroups[i].desc); - sfree(g_rdt->ngroups[i].desc); - strarray_free(g_rdt->ngroups[i].names, g_rdt->ngroups[i].num_names); + rdt->ngroups[i].desc); + sfree(rdt->ngroups[i].desc); - if (g_rdt->ngroups[i].proc_pids_array) { - for (size_t j = 0; j < g_rdt->ngroups[i].num_names; ++j) { - if (NULL == g_rdt->ngroups[i].proc_pids_array[j].pids) + strarray_free(rdt->ngroups[i].names, rdt->ngroups[i].num_names); + + if (rdt->ngroups[i].proc_pids_array) { + for (size_t j = 0; j < rdt->ngroups[i].num_names; ++j) { + if (NULL == rdt->ngroups[i].proc_pids_array[j].pids) continue; - pids_list_free(g_rdt->ngroups[i].proc_pids_array[j].pids); + pids_list_free(rdt->ngroups[i].proc_pids_array[j].pids); } - sfree(g_rdt->ngroups[i].proc_pids_array); + sfree(rdt->ngroups[i].proc_pids_array); } - g_rdt->ngroups[i].num_names = 0; - sfree(g_rdt->pngroups[i]); + rdt->ngroups[i].num_names = 0; + sfree(rdt->pngroups[i]); } } #endif /* LIBPQOS2 */ @@ -601,7 +617,7 @@ static int rdt_config_cgroups(oconfig_item_t *item) { } #ifdef LIBPQOS2 -static int rdt_config_ngroups(const oconfig_item_t *item) { +static int rdt_config_ngroups(rdt_ctx_t *rdt, const oconfig_item_t *item) { int n = 0; enum pqos_mon_event events = 0; @@ -621,22 +637,26 @@ static int rdt_config_ngroups(const oconfig_item_t *item) { DEBUG(RDT_PLUGIN ": [%d]: %s", j, item->values[j].value.string); } - n = oconfig_to_ngroups(item, g_rdt->ngroups, RDT_MAX_NAMES_GROUPS); + n = oconfig_to_ngroups(item, rdt->ngroups, RDT_MAX_NAMES_GROUPS); if (n < 0) { - rdt_free_ngroups(); + rdt_free_ngroups(rdt); ERROR(RDT_PLUGIN ": Error parsing process name groups configuration."); return -EINVAL; } /* validate configured process name values */ for (int group_idx = 0; group_idx < n; group_idx++) { - for (size_t name_idx = 0; name_idx < g_rdt->ngroups[group_idx].num_names; + DEBUG(RDT_PLUGIN ": checking group [%d]: %s", group_idx, + rdt->ngroups[group_idx].desc); + for (size_t name_idx = 0; name_idx < rdt->ngroups[group_idx].num_names; name_idx++) { - if (!rdt_is_proc_name_valid(g_rdt->ngroups[group_idx].names[name_idx])) { + DEBUG(RDT_PLUGIN ": checking process name [%zu]: %s", name_idx, + rdt->ngroups[group_idx].names[name_idx]); + if (!rdt_is_proc_name_valid(rdt->ngroups[group_idx].names[name_idx])) { ERROR(RDT_PLUGIN ": Process name group '%s' contains invalid name '%s'", - g_rdt->ngroups[group_idx].desc, - g_rdt->ngroups[group_idx].names[name_idx]); - rdt_free_ngroups(); + rdt->ngroups[group_idx].desc, + rdt->ngroups[group_idx].names[name_idx]); + rdt_free_ngroups(rdt); return -EINVAL; } } @@ -648,29 +668,29 @@ static int rdt_config_ngroups(const oconfig_item_t *item) { } /* Get all available events on this platform */ - for (unsigned i = 0; i < g_rdt->cap_mon->u.mon->num_events; i++) - events |= g_rdt->cap_mon->u.mon->events[i].type; + for (unsigned i = 0; i < rdt->cap_mon->u.mon->num_events; i++) + events |= rdt->cap_mon->u.mon->events[i].type; events &= ~(PQOS_PERF_EVENT_LLC_MISS); DEBUG(RDT_PLUGIN ": Available events to monitor: %#x", events); - g_rdt->num_ngroups = n; + rdt->num_ngroups = n; for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { - int found = ngroup_cmp(&g_rdt->ngroups[j], &g_rdt->ngroups[i]); + int found = ngroup_cmp(&rdt->ngroups[j], &rdt->ngroups[i]); if (found != 0) { - rdt_free_ngroups(); + rdt_free_ngroups(rdt); ERROR(RDT_PLUGIN ": Cannot monitor same process name in different groups."); return -EINVAL; } } - g_rdt->ngroups[i].events = events; - g_rdt->pngroups[i] = calloc(1, sizeof(*g_rdt->pngroups[i])); - if (g_rdt->pngroups[i] == NULL) { - rdt_free_ngroups(); + rdt->ngroups[i].events = events; + rdt->pngroups[i] = calloc(1, sizeof(*rdt->pngroups[i])); + if (rdt->pngroups[i] == NULL) { + rdt_free_ngroups(rdt); ERROR(RDT_PLUGIN ": Failed to allocate memory for process name monitoring data."); return -ENOMEM; @@ -1136,7 +1156,7 @@ static int rdt_config(oconfig_item_t *ci) { return 0; } - if (rdt_config_ngroups(child) != 0) { + if (rdt_config_ngroups(g_rdt, child) != 0) { g_state = CONFIGURATION_ERROR; /* if we return -1 at this point collectd reports a failure in configuration and @@ -1658,7 +1678,7 @@ static int rdt_shutdown(void) { rdt_free_cgroups(); #ifdef LIBPQOS2 - rdt_free_ngroups(); + rdt_free_ngroups(g_rdt); #endif /* LIBPQOS2 */ sfree(g_rdt); diff --git a/src/intel_rdt_test.c b/src/intel_rdt_test.c index 786fa9f6..42d03c7d 100644 --- a/src/intel_rdt_test.c +++ b/src/intel_rdt_test.c @@ -81,8 +81,6 @@ int pqos_cap_get_type(const struct pqos_cap *cap, const enum pqos_cap_type type, int pqos_cap_get(const struct pqos_cap **cap, const struct pqos_cpuinfo **cpu) { return 0; } -#endif /* LIBPQOS2 */ - /*************************************************************************** * helper functions */ @@ -113,75 +111,6 @@ pids_list_t *pids_list_get_element(pids_list_t *list, const size_t index) { return list; } -/* - * NAME - * pids_list_find_element - * - * DESCRIPTION - * Gets index of element in the list matching - * given pid. Assumes PIDs are unique, stops searching - * on the first match. - * - * PARAMETERS - * `list' Pids list - * `pid' PID number to find - * - * RETURN VALUE - * Index of list element holding given PID. - */ -int pids_list_find_element(pids_list_t *list, const pid_t pid) { - assert(list); - int result = -1; - size_t current = 0; - while (list != NULL) { - if (list->pid == pid) { - result = current; - break; - } - list = list->next; - } - return result; -} - -/* - * NAME - * pids_list_has_element - * - * DESCRIPTION - * Checks if the list contains given pid. - * Wrapper for pids_list_find_element function. - * Used to make tests easier to read. - * - * PARAMETERS - * `list' Pids list - * `pid' PID number to find - * - * RETURN VALUE - * 1 if list contains given PID - * 0 if list does not contain given PID - */ -int pids_list_has_element(pids_list_t *list, const pid_t pid) { - return pids_list_find_element(list, pid) >= 0 ? 1 : 0; -} - -/* - * NAME - * pids_list_free_all - * - * DESCRIPTION - * Frees memory allocated in the given list - * - * PARAMETERS - * `list' Pids list - */ -void pids_list_free_all(pids_list_t *list) { - while (list) { - pids_list_t *previous = list; - list = list->next; - free(previous); - } -} - typedef struct stub_proc_pid { proc_comm_t comm; pid_t pid; @@ -209,9 +138,8 @@ static const char *proc_fs = "/tmp/procfs_stub"; */ int stub_procfs_setup(const stub_proc_pid_t *proc_pids_array, const size_t proc_pids_array_length) { - if (mkdir(proc_fs, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) { + if (mkdir(proc_fs, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) return -1; - } char path[256]; for (size_t i = 0; i < proc_pids_array_length; ++i) { @@ -222,9 +150,8 @@ int stub_procfs_setup(const stub_proc_pid_t *proc_pids_array, strncat(path, "/comm", STATIC_ARRAY_SIZE(path) - strlen(path) - 1); FILE *fp = fopen(path, "w"); - if (!fp) { + if (!fp) return -2; - } fwrite(proc_pids_array[i].comm, sizeof(char), strlen(proc_pids_array[i].comm), fp); fclose(fp); @@ -258,10 +185,52 @@ int stub_procfs_teardown() { #define MAX_PID 4194304 #define MAX_PID_STR "4194304" +rdt_ctx_t *stub_rdt_setup() { + + rdt_ctx_t *rdt = calloc(1, sizeof(*rdt)); + struct pqos_cpuinfo *pqos_cpu = calloc(1, sizeof(*pqos_cpu)); + struct pqos_cap *pqos_cap = calloc(1, sizeof(*pqos_cap)); + struct pqos_cap_mon *mon = calloc(1, sizeof(*mon)); + struct pqos_capability *cap_mon = calloc(1, sizeof(*cap_mon)); + + cap_mon->u.mon = mon; + rdt->pqos_cap = pqos_cap; + rdt->pqos_cpu = pqos_cpu; + rdt->cap_mon = cap_mon; + + return rdt; +} + +void stub_rdt_teardown(rdt_ctx_t *rdt) { + free(rdt->cap_mon->u.mon); + free((void *)rdt->cap_mon); + free((void *)rdt->pqos_cpu); + free((void *)rdt->pqos_cap); + free(rdt); +} + /*************************************************************************** * tests */ -DEF_TEST(add_proc_pid_empty_list) { +DEF_TEST(initialize_proc_pids__on_nullptr) { + /* setup */ + const char *procs_names_array[] = {"proc1", "proc2", "proc3"}; + const size_t procs_names_array_size = STATIC_ARRAY_SIZE(procs_names_array); + proc_pids_t *proc_pids_array = NULL; + + /* check */ + int result = initialize_proc_pids(procs_names_array, procs_names_array_size, + &proc_pids_array); + EXPECT_EQ_INT(0, result); + for (size_t i = 0; i < procs_names_array_size; ++i) + EXPECT_EQ_STR(procs_names_array[i], proc_pids_array[i].proccess_name); + + /* cleanup */ + free(proc_pids_array); + return 0; +} + +DEF_TEST(add_proc_pid__empty_list) { /* setup */ proc_pids_t proc_pids_instance; proc_pids_instance.pids = NULL; @@ -273,20 +242,19 @@ DEF_TEST(add_proc_pid_empty_list) { EXPECT_EQ_INT(pid, added->pid); /* cleanup */ - pids_list_free_all(proc_pids_instance.pids); + pids_list_free(proc_pids_instance.pids); return 0; } -DEF_TEST(add_proc_pid_non_empty_list) { +DEF_TEST(add_proc_pid__non_empty_list) { /* setup */ proc_pids_t proc_pids_instance; proc_pids_instance.pids = NULL; pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; /* check */ - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) { + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) pids_list_add_pid(&proc_pids_instance.pids, pids[i]); - } for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) { pids_list_t *added = pids_list_get_element(proc_pids_instance.pids, i); @@ -294,11 +262,80 @@ DEF_TEST(add_proc_pid_non_empty_list) { } /* cleanup */ - pids_list_free_all(proc_pids_instance.pids); + pids_list_free(proc_pids_instance.pids); + return 0; +} + +DEF_TEST(pids_list_to_array__non_empty_list) { + /* setup */ + pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pids_list_t *pids_list = NULL; + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) + pids_list_add_pid(&pids_list, pids[i]); + + /* check */ + pid_t target_array[STATIC_ARRAY_SIZE(pids)]; + pids_list_to_array(target_array, pids_list, STATIC_ARRAY_SIZE(target_array)); + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) + EXPECT_EQ_INT(pids[i], target_array[i]); + + /* cleanup */ + pids_list_free(pids_list); return 0; } -DEF_TEST(get_pid_number_valid_dir) { +DEF_TEST(pids_list_add_pids_list__non_empty_lists) { + /* setup */ + pid_t pids_array_1[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pid_t pids_array_2[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; + pids_list_t *pids_list_1 = NULL; + pids_list_t *pids_list_2 = NULL; + size_t increase = 0; + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) { + pids_list_add_pid(&pids_list_1, pids_array_1[i]); + pids_list_add_pid(&pids_list_2, pids_array_2[i]); + } + + /* check */ + int result = pids_list_add_pids_list(&pids_list_1, pids_list_2, &increase); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_2), increase); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) { + EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_1[i])); + EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_2[i])); + } + + /* setup */ + pids_list_free(pids_list_1); + pids_list_free(pids_list_2); + return 0; +} + +DEF_TEST(pids_list_add_pids_list__add_to_empty) { + /* setup */ + pid_t pids_array[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; + pids_list_t *pids_list_1 = NULL; + pids_list_t *pids_list_2 = NULL; + size_t increase = 0; + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i) + pids_list_add_pid(&pids_list_2, pids_array[i]); + + /* check */ + int result = pids_list_add_pids_list(&pids_list_1, pids_list_2, &increase); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array), increase); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i) + EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array[i])); + + /* setup */ + pids_list_free(pids_list_1); + pids_list_free(pids_list_2); + return 0; +} + +DEF_TEST(get_pid_number__valid_dir) { /* setup */ struct dirent d; sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); @@ -315,7 +352,7 @@ DEF_TEST(get_pid_number_valid_dir) { return 0; } -DEF_TEST(get_pid_number_invalid_dir_name) { +DEF_TEST(get_pid_number__invalid_dir_name) { /* setup */ struct dirent d; sstrncpy(d.d_name, "invalid", STATIC_ARRAY_SIZE(d.d_name)); @@ -325,14 +362,14 @@ DEF_TEST(get_pid_number_invalid_dir_name) { /* check */ int pid_conversion = get_pid_number(&d, &pid); - EXPECT_EQ_INT(-2, pid_conversion); + EXPECT_EQ_INT(-1, pid_conversion); EXPECT_EQ_INT(0, pid); /* cleanup */ return 0; } -DEF_TEST(read_proc_name_valid_name) { +DEF_TEST(read_proc_name__valid_name) { /* setup */ stub_proc_pid_t pp_stubs[] = {{"proc1", MAX_PID}}; stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs)); @@ -352,7 +389,7 @@ DEF_TEST(read_proc_name_valid_name) { return 0; } -DEF_TEST(read_proc_name_invalid_name) { +DEF_TEST(read_proc_name__invalid_name) { /* setup */ struct dirent d; sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); @@ -368,7 +405,7 @@ DEF_TEST(read_proc_name_invalid_name) { return 0; } -DEF_TEST(fetch_pids_for_procs_one_proc_many_pid) { +DEF_TEST(fetch_pids_for_procs__one_proc_many_pid) { /* setup */ const char *proc_names[] = {"proc1"}; stub_proc_pid_t pp_stubs[] = {{"proc1", 1007}, @@ -388,25 +425,23 @@ DEF_TEST(fetch_pids_for_procs_one_proc_many_pid) { EXPECT_EQ_STR(proc_names[0], output[0].proccess_name); for (size_t i = 0; i < STATIC_ARRAY_SIZE(pp_stubs); ++i) { - if (0 == strcmp(pp_stubs[i].comm, proc_names[0])) { + if (0 == strcmp(pp_stubs[i].comm, proc_names[0])) /* check if proc struct has correct pids */ - EXPECT_EQ_INT(pids_list_has_element(output[0].pids, pp_stubs[i].pid), 1); - } else { + EXPECT_EQ_INT(pids_list_contains_pid(output[0].pids, pp_stubs[i].pid), 1); + else /* check if proc struct has no incorrect pids */ - EXPECT_EQ_INT(pids_list_has_element(output[0].pids, pp_stubs[i].pid), 0); - } + EXPECT_EQ_INT(pids_list_contains_pid(output[0].pids, pp_stubs[i].pid), 0); } /* cleanup */ - for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) { - pids_list_free_all(output[i].pids); - } + for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) + pids_list_free(output[i].pids); free(output); stub_procfs_teardown(); return 0; } -DEF_TEST(fetch_pids_for_procs_many_proc_many_pid) { +DEF_TEST(fetch_pids_for_procs__many_proc_many_pid) { /* setup */ const char *proc_names[] = {"proc1", "proc2", "proc3"}; stub_proc_pid_t pp_stubs[] = { @@ -428,37 +463,347 @@ DEF_TEST(fetch_pids_for_procs_many_proc_many_pid) { EXPECT_EQ_STR(proc_names[i], output[i].proccess_name); for (size_t j = 0; j < STATIC_ARRAY_SIZE(pp_stubs); ++j) { - if (0 == strcmp(pp_stubs[j].comm, proc_names[i])) { + if (0 == strcmp(pp_stubs[j].comm, proc_names[i])) /* check if proc struct has correct pids */ - EXPECT_EQ_INT(pids_list_has_element(output[i].pids, pp_stubs[j].pid), + EXPECT_EQ_INT(pids_list_contains_pid(output[i].pids, pp_stubs[j].pid), 1); - } else { + else /* check if proc struct has no incorrect pids */ - EXPECT_EQ_INT(pids_list_has_element(output[i].pids, pp_stubs[j].pid), + EXPECT_EQ_INT(pids_list_contains_pid(output[i].pids, pp_stubs[j].pid), 0); - } } } /* cleanup */ - for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) { - pids_list_free_all(output[i].pids); - } + for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) + pids_list_free(output[i].pids); free(output); stub_procfs_teardown(); return 0; } +DEF_TEST(rdt_config_ngroups__one_process) { + /* setup */ + rdt_ctx_t *rdt = stub_rdt_setup(); + + oconfig_value_t values[] = { + {.value.string = "proc1", .type = OCONFIG_TYPE_STRING}, + }; + oconfig_item_t config_item = { + .values = values, .values_num = STATIC_ARRAY_SIZE(values), + }; + + /* check */ + int result = rdt_config_ngroups(rdt, &config_item); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_STR(values[0].value.string, rdt->ngroups[0].desc); + EXPECT_EQ_INT(1, rdt->num_ngroups); + + /* cleanup */ + rdt_free_ngroups(rdt); + stub_rdt_teardown(rdt); + + return 0; +} + +DEF_TEST(rdt_config_ngroups__two_groups) { + /* setup */ + rdt_ctx_t *rdt = stub_rdt_setup(); + + oconfig_value_t values[] = { + {.value.string = "proc11,proc12,proc13", .type = OCONFIG_TYPE_STRING}, + {.value.string = "proc21,proc22,proc23", .type = OCONFIG_TYPE_STRING}, + }; + oconfig_item_t config_item = { + .values = values, .values_num = STATIC_ARRAY_SIZE(values), + }; + + /* check */ + int result = rdt_config_ngroups(rdt, &config_item); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(2, rdt->num_ngroups); + EXPECT_EQ_STR("proc11,proc12,proc13", rdt->ngroups[0].desc); + EXPECT_EQ_STR("proc21,proc22,proc23", rdt->ngroups[1].desc); + EXPECT_EQ_STR("proc11", rdt->ngroups[0].names[0]); + EXPECT_EQ_STR("proc12", rdt->ngroups[0].names[1]); + EXPECT_EQ_STR("proc13", rdt->ngroups[0].names[2]); + EXPECT_EQ_STR("proc21", rdt->ngroups[1].names[0]); + EXPECT_EQ_STR("proc22", rdt->ngroups[1].names[1]); + EXPECT_EQ_STR("proc23", rdt->ngroups[1].names[2]); + + /* cleanup */ + rdt_free_ngroups(rdt); + stub_rdt_teardown(rdt); + + return 0; +} + +DEF_TEST(rdt_config_ngroups__too_long_proc_name) { + /* setup */ + rdt_ctx_t *rdt = stub_rdt_setup(); + + oconfig_value_t values[] = { + {.value.string = "_seventeen_chars_", .type = OCONFIG_TYPE_STRING}, + }; + oconfig_item_t config_item = { + .values = values, .values_num = STATIC_ARRAY_SIZE(values), + }; + + /* check */ + int result = rdt_config_ngroups(rdt, &config_item); + EXPECT_EQ_INT(-EINVAL, result); + + /* cleanup */ + stub_rdt_teardown(rdt); + + return 0; +} + +DEF_TEST(rdt_config_ngroups__duplicate_proc_name_between_groups) { + /* setup */ + rdt_ctx_t *rdt = stub_rdt_setup(); + + oconfig_value_t values[] = { + {.value.string = "proc11,proc12,proc", .type = OCONFIG_TYPE_STRING}, + {.value.string = "proc21,proc,proc23", .type = OCONFIG_TYPE_STRING}, + }; + oconfig_item_t config_item = { + .values = values, .values_num = STATIC_ARRAY_SIZE(values), + }; + + /* check */ + int result = rdt_config_ngroups(rdt, &config_item); + EXPECT_EQ_INT(-EINVAL, result); + + /* cleanup */ + stub_rdt_teardown(rdt); + + return 0; +} + +DEF_TEST(rdt_config_ngroups__duplicate_proc_name_in_group) { + /* setup */ + rdt_ctx_t *rdt = stub_rdt_setup(); + + oconfig_value_t values[] = { + {.value.string = "proc11,proc,proc,proc14", .type = OCONFIG_TYPE_STRING}, + }; + oconfig_item_t config_item = { + .values = values, .values_num = STATIC_ARRAY_SIZE(values), + }; + + /* check */ + int result = rdt_config_ngroups(rdt, &config_item); + EXPECT_EQ_INT(-EINVAL, result); + + /* cleanup */ + stub_rdt_teardown(rdt); + + return 0; +} + +DEF_TEST(rdt_config_ngroups__empty_group) { + /* setup */ + rdt_ctx_t *rdt = stub_rdt_setup(); + + oconfig_value_t values[] = { + {.value.string = "proc11,proc12,proc13", .type = OCONFIG_TYPE_STRING}, + {.value.string = "", .type = OCONFIG_TYPE_STRING}, + + }; + oconfig_item_t config_item = { + .values = values, .values_num = STATIC_ARRAY_SIZE(values), + }; + + /* check */ + int result = rdt_config_ngroups(rdt, &config_item); + EXPECT_EQ_INT(-EINVAL, result); + + /* cleanup */ + stub_rdt_teardown(rdt); + + return 0; +} + +DEF_TEST(rdt_config_ngroups__empty_proc_name) { + /* setup */ + rdt_ctx_t *rdt = stub_rdt_setup(); + + oconfig_value_t values[] = { + {.value.string = "proc11,,proc13", .type = OCONFIG_TYPE_STRING}, + }; + oconfig_item_t config_item = { + .values = values, .values_num = STATIC_ARRAY_SIZE(values), + }; + + /* check */ + int result = rdt_config_ngroups(rdt, &config_item); + EXPECT_EQ_INT(-EINVAL, result); + + /* cleanup */ + stub_rdt_teardown(rdt); + + return 0; +} + +DEF_TEST(rdt_pid_list_diff__all_changed) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pid_t pids_array_after[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; + pids_list_t *pids_list_before = NULL; + pids_list_t *pids_list_after = NULL; + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i) { + pids_list_add_pid(&pids_list_before, pids_array_before[i]); + pids_list_add_pid(&pids_list_after, pids_array_after[i]); + } + + pids_list_t *new_pids = NULL; + size_t new_pids_count = 0; + pids_list_t *lost_pids = NULL; + size_t lost_pids_count = 0; + + /* check */ + int result = rdt_pid_list_diff(pids_list_before, pids_list_after, &new_pids, + &new_pids_count, &lost_pids, &lost_pids_count); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_before), lost_pids_count); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_after), new_pids_count); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) { + EXPECT_EQ_INT(1, pids_list_contains_pid(new_pids, pids_array_after[i])); + EXPECT_EQ_INT(1, pids_list_contains_pid(lost_pids, pids_array_before[i])); + } + + /* cleanup */ + pids_list_free(pids_list_before); + pids_list_free(pids_list_after); + pids_list_free(new_pids); + pids_list_free(lost_pids); + + return 0; +} + +DEF_TEST(rdt_pid_list_diff__nothing_changed) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pids_list_t *pids_list_before = NULL; + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) { + pids_list_add_pid(&pids_list_before, pids_array_before[i]); + } + + pids_list_t *new_pids = NULL; + size_t new_pids_count = 0; + pids_list_t *lost_pids = NULL; + size_t lost_pids_count = 0; + + /* check */ + int result = rdt_pid_list_diff(pids_list_before, pids_list_before, &new_pids, + &new_pids_count, &lost_pids, &lost_pids_count); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(0, lost_pids_count); + EXPECT_EQ_INT(0, new_pids_count); + OK(NULL == new_pids); + OK(NULL == lost_pids); + + /* cleanup */ + pids_list_free(pids_list_before); + + return 0; +} + +DEF_TEST(rdt_pid_list_diff__one_added) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, + 1005, 1006, 1007, 1008}; + pids_list_t *pids_list_before = NULL; + pids_list_t *pids_list_after = NULL; + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) + pids_list_add_pid(&pids_list_before, pids_array_before[i]); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i) + pids_list_add_pid(&pids_list_after, pids_array_after[i]); + + pids_list_t *new_pids = NULL; + size_t new_pids_count = 0; + pids_list_t *lost_pids = NULL; + size_t lost_pids_count = 0; + + /* check */ + int result = rdt_pid_list_diff(pids_list_before, pids_list_after, &new_pids, + &new_pids_count, &lost_pids, &lost_pids_count); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(0, lost_pids_count); + EXPECT_EQ_INT(1, new_pids_count); + EXPECT_EQ_INT(1008, new_pids->pid); + + /* cleanup */ + pids_list_free(pids_list_before); + pids_list_free(pids_list_after); + pids_list_free(new_pids); + + return 0; +} + +DEF_TEST(rdt_pid_list_diff__one_removed) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, + 1005, 1006, 1007, 1008}; + pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pids_list_t *pids_list_before = NULL; + pids_list_t *pids_list_after = NULL; + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) + pids_list_add_pid(&pids_list_before, pids_array_before[i]); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i) + pids_list_add_pid(&pids_list_after, pids_array_after[i]); + + pids_list_t *new_pids = NULL; + size_t new_pids_count = 0; + pids_list_t *lost_pids = NULL; + size_t lost_pids_count = 0; + + /* check */ + int result = rdt_pid_list_diff(pids_list_before, pids_list_after, &new_pids, + &new_pids_count, &lost_pids, &lost_pids_count); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(1, lost_pids_count); + EXPECT_EQ_INT(0, new_pids_count); + EXPECT_EQ_INT(1008, lost_pids->pid); + + /* cleanup */ + pids_list_free(pids_list_before); + pids_list_free(pids_list_after); + pids_list_free(lost_pids); + + return 0; +} + int main(void) { stub_procfs_teardown(); - RUN_TEST(add_proc_pid_empty_list); - RUN_TEST(add_proc_pid_non_empty_list); - RUN_TEST(get_pid_number_valid_dir); - RUN_TEST(get_pid_number_invalid_dir_name); - RUN_TEST(read_proc_name_valid_name); - RUN_TEST(read_proc_name_invalid_name); - RUN_TEST(fetch_pids_for_procs_one_proc_many_pid); - RUN_TEST(fetch_pids_for_procs_many_proc_many_pid); + RUN_TEST(initialize_proc_pids__on_nullptr); + RUN_TEST(add_proc_pid__empty_list); + RUN_TEST(add_proc_pid__non_empty_list); + RUN_TEST(pids_list_to_array__non_empty_list); + RUN_TEST(pids_list_add_pids_list__non_empty_lists); + RUN_TEST(pids_list_add_pids_list__add_to_empty); + RUN_TEST(get_pid_number__valid_dir); + RUN_TEST(get_pid_number__invalid_dir_name); + RUN_TEST(read_proc_name__valid_name); + RUN_TEST(read_proc_name__invalid_name); + RUN_TEST(fetch_pids_for_procs__one_proc_many_pid); + RUN_TEST(fetch_pids_for_procs__many_proc_many_pid); + RUN_TEST(rdt_config_ngroups__one_process); + RUN_TEST(rdt_config_ngroups__two_groups); + RUN_TEST(rdt_config_ngroups__too_long_proc_name); + RUN_TEST(rdt_config_ngroups__duplicate_proc_name_between_groups); + RUN_TEST(rdt_config_ngroups__duplicate_proc_name_in_group); + RUN_TEST(rdt_config_ngroups__empty_group); + RUN_TEST(rdt_config_ngroups__empty_proc_name); + RUN_TEST(rdt_pid_list_diff__all_changed); + RUN_TEST(rdt_pid_list_diff__nothing_changed); + RUN_TEST(rdt_pid_list_diff__one_added); + RUN_TEST(rdt_pid_list_diff__one_removed); stub_procfs_teardown(); END_TEST; }