intel_rdt: update unit-tests for process monitoring
[collectd.git] / src / intel_rdt_test.c
1 #include "intel_rdt.c" /* sic */
2 #include "testing.h"
3 #include <sys/stat.h>
4
5 /***************************************************************************
6  * PQOS mocks
7  */
8 #if PQOS_VERSION >= 30000
9 int pqos_alloc_reset(const enum pqos_cdp_config l3_cdp_cfg,
10                      const enum pqos_cdp_config l2_cdp_cfg,
11                      const enum pqos_mba_config mba_cfg) {
12   return 0;
13 }
14 #elif PQOS_VERSION >= 2000
15 int pqos_alloc_reset(const enum pqos_cdp_config l3_cdp_cfg,
16                      const enum pqos_cdp_config l2_cdp_cfg) {
17   return 0;
18 }
19 #else
20 int pqos_alloc_reset(const enum pqos_cdp_config l3_cdp_cfg) {
21   return 0;
22 }
23 #endif
24
25 #ifdef LIBPQOS2
26 /***************************************************************************
27  * PQOS v2.0 mocks
28  */
29 int pqos_mon_reset(void) { return 0; }
30 int pqos_mon_assoc_get(const unsigned lcore, pqos_rmid_t *rmid) { return 0; }
31 int pqos_mon_start(const unsigned num_cores, const unsigned *cores,
32                    const enum pqos_mon_event event, void *context,
33                    struct pqos_mon_data *group) {
34   return 0;
35 }
36 int pqos_mon_start_pids(const unsigned num_pids, const pid_t *pids,
37                         const enum pqos_mon_event event, void *context,
38                         struct pqos_mon_data *group) {
39   return 0;
40 }
41 int pqos_mon_add_pids(const unsigned num_pids, const pid_t *pids,
42                       struct pqos_mon_data *group) {
43   return 0;
44 }
45 int pqos_mon_remove_pids(const unsigned num_pids, const pid_t *pids,
46                          struct pqos_mon_data *group) {
47   return 0;
48 }
49 int pqos_mon_stop(struct pqos_mon_data *group) { return 0; }
50 int pqos_mon_poll(struct pqos_mon_data **groups, const unsigned num_groups) {
51   return 0;
52 }
53 int pqos_alloc_assoc_set(const unsigned lcore, const unsigned class_id) {
54   return 0;
55 }
56 int pqos_alloc_assoc_get(const unsigned lcore, unsigned *class_id) { return 0; }
57 int pqos_alloc_assoc_set_pid(const pid_t task, const unsigned class_id) {
58   return 0;
59 }
60 int pqos_alloc_assoc_get_pid(const pid_t task, unsigned *class_id) { return 0; }
61 int pqos_alloc_assign(const unsigned technology, const unsigned *core_array,
62                       const unsigned core_num, unsigned *class_id) {
63   return 0;
64 }
65 int pqos_alloc_release(const unsigned *core_array, const unsigned core_num) {
66   return 0;
67 }
68 int pqos_alloc_assign_pid(const unsigned technology, const pid_t *task_array,
69                           const unsigned task_num, unsigned *class_id) {
70   return 0;
71 }
72 int pqos_alloc_release_pid(const pid_t *task_array, const unsigned task_num) {
73   return 0;
74 }
75 int pqos_init(const struct pqos_config *config) { return 0; }
76 int pqos_fini(void) { return 0; }
77 int pqos_cap_get_type(const struct pqos_cap *cap, const enum pqos_cap_type type,
78                       const struct pqos_capability **cap_item) {
79   return 0;
80 }
81 int pqos_cap_get(const struct pqos_cap **cap, const struct pqos_cpuinfo **cpu) {
82   return 0;
83 }
84 /***************************************************************************
85  * helper functions
86  */
87
88 /*
89  * NAME
90  *   pids_list_get_element
91  *
92  * DESCRIPTION
93  *   Gets list element at index position. Assumes list was created by
94  *   pids_list_add_pid function.
95  *
96  * PARAMETERS
97  *   `list'      Pids list
98  *   `index'     Position of desired element relative to given list pointer.
99  *
100  * RETURN VALUE
101  *   Pointer to element at index position.
102  *   NULL if index exceeds list's length.
103  */
104 pids_list_t *pids_list_get_element(pids_list_t *list, const size_t index) {
105   assert(list);
106   size_t current = 0;
107   while (list != NULL && current != index) {
108     list = list->next;
109     current++;
110   }
111   return list;
112 }
113
114 typedef struct stub_proc_pid {
115   proc_comm_t comm;
116   pid_t pid;
117 } stub_proc_pid_t;
118
119 static const char *proc_fs = "/tmp/procfs_stub";
120
121 /*
122  * NAME
123  *   stub_procfs_setup
124  *
125  * DESCRIPTION
126  *   Prepares testing environment by creating temporary
127  *   PID/comm file structure.
128  *
129  * PARAMETERS
130  *   `proc_pids_array'          Array of stub_proc_pid_t structs. Represents
131  *                              which PIDs should hold given process name.
132  *   `proc_pids_array_length'   Element count of input array.
133  *
134  * RETURN VALUE
135  *   0 on success.
136  *   -1 on base dir creation error.
137  *   -2 on comm file creation error.
138  */
139 int stub_procfs_setup(const stub_proc_pid_t *proc_pids_array,
140                       const size_t proc_pids_array_length) {
141   if (mkdir(proc_fs, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
142     return -1;
143   char path[256];
144
145   for (size_t i = 0; i < proc_pids_array_length; ++i) {
146     memset(path, 0, sizeof(path));
147     snprintf(path, STATIC_ARRAY_SIZE(path), "%s/%d", proc_fs,
148              proc_pids_array[i].pid);
149     mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
150     strncat(path, "/comm", STATIC_ARRAY_SIZE(path) - strlen(path) - 1);
151
152     FILE *fp = fopen(path, "w");
153     if (!fp)
154       return -2;
155     fwrite(proc_pids_array[i].comm, sizeof(char),
156            strlen(proc_pids_array[i].comm), fp);
157     fclose(fp);
158   }
159   return 0;
160 }
161
162 /*
163  * NAME
164  *   stub_procfs_teardown
165  *
166  * DESCRIPTION
167  *   Clears testing environment: removes stub proc files.
168  *   NOTE - This function could be implemented by usage of nftw, but this
169  *   would require #define _XOPEN_SOURCE 500, which
170  *   messes up intel_rdt includes.
171  *
172  * RETURN VALUE
173  *   system command result
174  */
175 int stub_procfs_teardown() {
176   char cmd[256];
177   sstrncpy(cmd, "rm -rf ", STATIC_ARRAY_SIZE(cmd));
178   strncat(cmd, proc_fs, STATIC_ARRAY_SIZE(cmd) - strlen(cmd) - 1);
179   return system(cmd);
180 }
181
182 /* Max PID value. More info:
183  * http://web.archive.org/web/20111209081734/http://research.cs.wisc.edu/condor/condorg/linux_scalability.html
184  */
185 #define MAX_PID 4194304
186 #define MAX_PID_STR "4194304"
187
188 rdt_ctx_t *stub_rdt_setup() {
189
190   rdt_ctx_t *rdt = calloc(1, sizeof(*rdt));
191   struct pqos_cpuinfo *pqos_cpu = calloc(1, sizeof(*pqos_cpu));
192   struct pqos_cap *pqos_cap = calloc(1, sizeof(*pqos_cap));
193   struct pqos_cap_mon *mon = calloc(1, sizeof(*mon));
194   struct pqos_capability *cap_mon = calloc(1, sizeof(*cap_mon));
195
196   cap_mon->u.mon = mon;
197   rdt->pqos_cap = pqos_cap;
198   rdt->pqos_cpu = pqos_cpu;
199   rdt->cap_mon = cap_mon;
200
201   return rdt;
202 }
203
204 void stub_rdt_teardown(rdt_ctx_t *rdt) {
205   free(rdt->cap_mon->u.mon);
206   free((void *)rdt->cap_mon);
207   free((void *)rdt->pqos_cpu);
208   free((void *)rdt->pqos_cap);
209   free(rdt);
210 }
211
212 /***************************************************************************
213  * tests
214  */
215 DEF_TEST(initialize_proc_pids__on_nullptr) {
216   /* setup */
217   const char *procs_names_array[] = {"proc1", "proc2", "proc3"};
218   const size_t procs_names_array_size = STATIC_ARRAY_SIZE(procs_names_array);
219   proc_pids_t *proc_pids_array = NULL;
220
221   /* check */
222   int result = initialize_proc_pids(procs_names_array, procs_names_array_size,
223                                     &proc_pids_array);
224   EXPECT_EQ_INT(0, result);
225   for (size_t i = 0; i < procs_names_array_size; ++i)
226     EXPECT_EQ_STR(procs_names_array[i], proc_pids_array[i].proccess_name);
227
228   /* cleanup */
229   free(proc_pids_array);
230   return 0;
231 }
232
233 DEF_TEST(add_proc_pid__empty_list) {
234   /* setup */
235   proc_pids_t proc_pids_instance;
236   proc_pids_instance.pids = NULL;
237   pid_t pid = 1234;
238
239   /* check */
240   pids_list_add_pid(&proc_pids_instance.pids, pid);
241   pids_list_t *added = pids_list_get_element(proc_pids_instance.pids, 0);
242   EXPECT_EQ_INT(pid, added->pid);
243
244   /* cleanup */
245   pids_list_free(proc_pids_instance.pids);
246   return 0;
247 }
248
249 DEF_TEST(add_proc_pid__non_empty_list) {
250   /* setup */
251   proc_pids_t proc_pids_instance;
252   proc_pids_instance.pids = NULL;
253   pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
254
255   /* check */
256   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i)
257     pids_list_add_pid(&proc_pids_instance.pids, pids[i]);
258
259   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) {
260     pids_list_t *added = pids_list_get_element(proc_pids_instance.pids, i);
261     EXPECT_EQ_INT(pids[i], added->pid);
262   }
263
264   /* cleanup */
265   pids_list_free(proc_pids_instance.pids);
266   return 0;
267 }
268
269 DEF_TEST(pids_list_to_array__non_empty_list) {
270   /* setup */
271   pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
272   pids_list_t *pids_list = NULL;
273   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i)
274     pids_list_add_pid(&pids_list, pids[i]);
275
276   /* check */
277   pid_t target_array[STATIC_ARRAY_SIZE(pids)];
278   pids_list_to_array(target_array, pids_list, STATIC_ARRAY_SIZE(target_array));
279   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i)
280     EXPECT_EQ_INT(pids[i], target_array[i]);
281
282   /* cleanup */
283   pids_list_free(pids_list);
284   return 0;
285 }
286
287 DEF_TEST(pids_list_add_pids_list__non_empty_lists) {
288   /* setup */
289   pid_t pids_array_1[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
290   pid_t pids_array_2[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
291   pids_list_t *pids_list_1 = NULL;
292   pids_list_t *pids_list_2 = NULL;
293   size_t increase = 0;
294   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) {
295     pids_list_add_pid(&pids_list_1, pids_array_1[i]);
296     pids_list_add_pid(&pids_list_2, pids_array_2[i]);
297   }
298
299   /* check */
300   int result = pids_list_add_pids_list(&pids_list_1, pids_list_2, &increase);
301   EXPECT_EQ_INT(0, result);
302   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_2), increase);
303
304   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) {
305     EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_1[i]));
306     EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_2[i]));
307   }
308
309   /* setup */
310   pids_list_free(pids_list_1);
311   pids_list_free(pids_list_2);
312   return 0;
313 }
314
315 DEF_TEST(pids_list_add_pids_list__add_to_empty) {
316   /* setup */
317   pid_t pids_array[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
318   pids_list_t *pids_list_1 = NULL;
319   pids_list_t *pids_list_2 = NULL;
320   size_t increase = 0;
321   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i)
322     pids_list_add_pid(&pids_list_2, pids_array[i]);
323
324   /* check */
325   int result = pids_list_add_pids_list(&pids_list_1, pids_list_2, &increase);
326   EXPECT_EQ_INT(0, result);
327   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array), increase);
328
329   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i)
330     EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array[i]));
331
332   /* setup */
333   pids_list_free(pids_list_1);
334   pids_list_free(pids_list_2);
335   return 0;
336 }
337
338 DEF_TEST(get_pid_number__valid_dir) {
339   /* setup */
340   struct dirent d;
341   sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
342   d.d_type = DT_DIR;
343   pid_t pid = 0;
344
345   /* check */
346   int pid_conversion = get_pid_number(&d, &pid);
347
348   EXPECT_EQ_INT(0, pid_conversion);
349   EXPECT_EQ_INT(MAX_PID, pid);
350
351   /* cleanup */
352   return 0;
353 }
354
355 DEF_TEST(get_pid_number__invalid_dir_name) {
356   /* setup */
357   struct dirent d;
358   sstrncpy(d.d_name, "invalid", STATIC_ARRAY_SIZE(d.d_name));
359   d.d_type = DT_DIR;
360   pid_t pid = 0;
361
362   /* check */
363   int pid_conversion = get_pid_number(&d, &pid);
364
365   EXPECT_EQ_INT(-1, pid_conversion);
366   EXPECT_EQ_INT(0, pid);
367
368   /* cleanup */
369   return 0;
370 }
371
372 DEF_TEST(read_proc_name__valid_name) {
373   /* setup */
374   stub_proc_pid_t pp_stubs[] = {{"proc1", MAX_PID}};
375   stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
376   struct dirent d;
377   sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
378   d.d_type = DT_DIR;
379
380   /* check */
381   proc_comm_t comm;
382   int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm));
383
384   EXPECT_EQ_INT(strlen(pp_stubs[0].comm), read_result);
385   EXPECT_EQ_STR(pp_stubs[0].comm, comm);
386
387   /* cleanup */
388   stub_procfs_teardown();
389   return 0;
390 }
391
392 DEF_TEST(read_proc_name__invalid_name) {
393   /* setup */
394   struct dirent d;
395   sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
396   d.d_type = DT_DIR;
397
398   /* check */
399   proc_comm_t comm;
400   int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm));
401
402   EXPECT_EQ_INT(-1, read_result);
403
404   /* cleanup */
405   return 0;
406 }
407
408 DEF_TEST(fetch_pids_for_procs__one_proc_many_pid) {
409   /* setup */
410   const char *proc_names[] = {"proc1"};
411   stub_proc_pid_t pp_stubs[] = {{"proc1", 1007},
412                                 {"proc1", 1008},
413                                 {"proc1", 1009},
414                                 {"proc2", 1010},
415                                 {"proc3", 1011}};
416   stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
417   proc_pids_t *output = NULL;
418
419   /* check */
420   int result = fetch_pids_for_procs(proc_fs, proc_names,
421                                     STATIC_ARRAY_SIZE(proc_names), &output);
422   EXPECT_EQ_INT(0, result);
423
424   /* proc name check */
425   EXPECT_EQ_STR(proc_names[0], output[0].proccess_name);
426
427   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pp_stubs); ++i) {
428     if (0 == strcmp(pp_stubs[i].comm, proc_names[0]))
429       /* check if proc struct has correct pids */
430       EXPECT_EQ_INT(pids_list_contains_pid(output[0].pids, pp_stubs[i].pid), 1);
431     else
432       /* check if proc struct has no incorrect pids */
433       EXPECT_EQ_INT(pids_list_contains_pid(output[0].pids, pp_stubs[i].pid), 0);
434   }
435
436   /* cleanup */
437   for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i)
438     pids_list_free(output[i].pids);
439   free(output);
440   stub_procfs_teardown();
441   return 0;
442 }
443
444 DEF_TEST(fetch_pids_for_procs__many_proc_many_pid) {
445   /* setup */
446   const char *proc_names[] = {"proc1", "proc2", "proc3"};
447   stub_proc_pid_t pp_stubs[] = {
448       {"proc1", 1007}, {"proc1", 1008}, {"proc1", 1009}, {"proc2", 2007},
449       {"proc2", 2008}, {"proc2", 2009}, {"proc3", 3007}, {"proc3", 3008},
450       {"proc3", 3009}, {"proc4", 4007}, {"proc4", 4008}, {"proc4", 4009},
451       {"proc5", 5007}, {"proc5", 5008}, {"proc5", 5009}};
452   stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
453   proc_pids_t *output = NULL;
454
455   /* check */
456   int result = fetch_pids_for_procs(proc_fs, proc_names,
457                                     STATIC_ARRAY_SIZE(proc_names), &output);
458   EXPECT_EQ_INT(0, result);
459
460   for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) {
461
462     /* proc name check */
463     EXPECT_EQ_STR(proc_names[i], output[i].proccess_name);
464
465     for (size_t j = 0; j < STATIC_ARRAY_SIZE(pp_stubs); ++j) {
466       if (0 == strcmp(pp_stubs[j].comm, proc_names[i]))
467         /* check if proc struct has correct pids */
468         EXPECT_EQ_INT(pids_list_contains_pid(output[i].pids, pp_stubs[j].pid),
469                       1);
470       else
471         /* check if proc struct has no incorrect pids */
472         EXPECT_EQ_INT(pids_list_contains_pid(output[i].pids, pp_stubs[j].pid),
473                       0);
474     }
475   }
476
477   /* cleanup */
478   for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i)
479     pids_list_free(output[i].pids);
480   free(output);
481   stub_procfs_teardown();
482   return 0;
483 }
484
485 DEF_TEST(rdt_config_ngroups__one_process) {
486   /* setup */
487   rdt_ctx_t *rdt = stub_rdt_setup();
488
489   oconfig_value_t values[] = {
490       {.value.string = "proc1", .type = OCONFIG_TYPE_STRING},
491   };
492   oconfig_item_t config_item = {
493       .values = values, .values_num = STATIC_ARRAY_SIZE(values),
494   };
495
496   /* check */
497   int result = rdt_config_ngroups(rdt, &config_item);
498   EXPECT_EQ_INT(0, result);
499   EXPECT_EQ_STR(values[0].value.string, rdt->ngroups[0].desc);
500   EXPECT_EQ_INT(1, rdt->num_ngroups);
501
502   /* cleanup */
503   rdt_free_ngroups(rdt);
504   stub_rdt_teardown(rdt);
505
506   return 0;
507 }
508
509 DEF_TEST(rdt_config_ngroups__two_groups) {
510   /* setup */
511   rdt_ctx_t *rdt = stub_rdt_setup();
512
513   oconfig_value_t values[] = {
514       {.value.string = "proc11,proc12,proc13", .type = OCONFIG_TYPE_STRING},
515       {.value.string = "proc21,proc22,proc23", .type = OCONFIG_TYPE_STRING},
516   };
517   oconfig_item_t config_item = {
518       .values = values, .values_num = STATIC_ARRAY_SIZE(values),
519   };
520
521   /* check */
522   int result = rdt_config_ngroups(rdt, &config_item);
523   EXPECT_EQ_INT(0, result);
524   EXPECT_EQ_INT(2, rdt->num_ngroups);
525   EXPECT_EQ_STR("proc11,proc12,proc13", rdt->ngroups[0].desc);
526   EXPECT_EQ_STR("proc21,proc22,proc23", rdt->ngroups[1].desc);
527   EXPECT_EQ_STR("proc11", rdt->ngroups[0].names[0]);
528   EXPECT_EQ_STR("proc12", rdt->ngroups[0].names[1]);
529   EXPECT_EQ_STR("proc13", rdt->ngroups[0].names[2]);
530   EXPECT_EQ_STR("proc21", rdt->ngroups[1].names[0]);
531   EXPECT_EQ_STR("proc22", rdt->ngroups[1].names[1]);
532   EXPECT_EQ_STR("proc23", rdt->ngroups[1].names[2]);
533
534   /* cleanup */
535   rdt_free_ngroups(rdt);
536   stub_rdt_teardown(rdt);
537
538   return 0;
539 }
540
541 DEF_TEST(rdt_config_ngroups__too_long_proc_name) {
542   /* setup */
543   rdt_ctx_t *rdt = stub_rdt_setup();
544
545   oconfig_value_t values[] = {
546       {.value.string = "_seventeen_chars_", .type = OCONFIG_TYPE_STRING},
547   };
548   oconfig_item_t config_item = {
549       .values = values, .values_num = STATIC_ARRAY_SIZE(values),
550   };
551
552   /* check */
553   int result = rdt_config_ngroups(rdt, &config_item);
554   EXPECT_EQ_INT(-EINVAL, result);
555
556   /* cleanup */
557   stub_rdt_teardown(rdt);
558
559   return 0;
560 }
561
562 DEF_TEST(rdt_config_ngroups__duplicate_proc_name_between_groups) {
563   /* setup */
564   rdt_ctx_t *rdt = stub_rdt_setup();
565
566   oconfig_value_t values[] = {
567       {.value.string = "proc11,proc12,proc", .type = OCONFIG_TYPE_STRING},
568       {.value.string = "proc21,proc,proc23", .type = OCONFIG_TYPE_STRING},
569   };
570   oconfig_item_t config_item = {
571       .values = values, .values_num = STATIC_ARRAY_SIZE(values),
572   };
573
574   /* check */
575   int result = rdt_config_ngroups(rdt, &config_item);
576   EXPECT_EQ_INT(-EINVAL, result);
577
578   /* cleanup */
579   stub_rdt_teardown(rdt);
580
581   return 0;
582 }
583
584 DEF_TEST(rdt_config_ngroups__duplicate_proc_name_in_group) {
585   /* setup */
586   rdt_ctx_t *rdt = stub_rdt_setup();
587
588   oconfig_value_t values[] = {
589       {.value.string = "proc11,proc,proc,proc14", .type = OCONFIG_TYPE_STRING},
590   };
591   oconfig_item_t config_item = {
592       .values = values, .values_num = STATIC_ARRAY_SIZE(values),
593   };
594
595   /* check */
596   int result = rdt_config_ngroups(rdt, &config_item);
597   EXPECT_EQ_INT(-EINVAL, result);
598
599   /* cleanup */
600   stub_rdt_teardown(rdt);
601
602   return 0;
603 }
604
605 DEF_TEST(rdt_config_ngroups__empty_group) {
606   /* setup */
607   rdt_ctx_t *rdt = stub_rdt_setup();
608
609   oconfig_value_t values[] = {
610       {.value.string = "proc11,proc12,proc13", .type = OCONFIG_TYPE_STRING},
611       {.value.string = "", .type = OCONFIG_TYPE_STRING},
612
613   };
614   oconfig_item_t config_item = {
615       .values = values, .values_num = STATIC_ARRAY_SIZE(values),
616   };
617
618   /* check */
619   int result = rdt_config_ngroups(rdt, &config_item);
620   EXPECT_EQ_INT(-EINVAL, result);
621
622   /* cleanup */
623   stub_rdt_teardown(rdt);
624
625   return 0;
626 }
627
628 DEF_TEST(rdt_config_ngroups__empty_proc_name) {
629   /* setup */
630   rdt_ctx_t *rdt = stub_rdt_setup();
631
632   oconfig_value_t values[] = {
633       {.value.string = "proc11,,proc13", .type = OCONFIG_TYPE_STRING},
634   };
635   oconfig_item_t config_item = {
636       .values = values, .values_num = STATIC_ARRAY_SIZE(values),
637   };
638
639   /* check */
640   int result = rdt_config_ngroups(rdt, &config_item);
641   EXPECT_EQ_INT(-EINVAL, result);
642
643   /* cleanup */
644   stub_rdt_teardown(rdt);
645
646   return 0;
647 }
648
649 DEF_TEST(rdt_pid_list_diff__all_changed) {
650   /* setup */
651   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
652   pid_t pids_array_after[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
653   pids_list_t *pids_list_before = NULL;
654   pids_list_t *pids_list_after = NULL;
655   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i) {
656     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
657     pids_list_add_pid(&pids_list_after, pids_array_after[i]);
658   }
659
660   pids_list_t *new_pids = NULL;
661   size_t new_pids_count = 0;
662   pids_list_t *lost_pids = NULL;
663   size_t lost_pids_count = 0;
664
665   /* check */
666   int result = rdt_pid_list_diff(pids_list_before, pids_list_after, &new_pids,
667                                  &new_pids_count, &lost_pids, &lost_pids_count);
668   EXPECT_EQ_INT(0, result);
669   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_before), lost_pids_count);
670   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_after), new_pids_count);
671
672   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) {
673     EXPECT_EQ_INT(1, pids_list_contains_pid(new_pids, pids_array_after[i]));
674     EXPECT_EQ_INT(1, pids_list_contains_pid(lost_pids, pids_array_before[i]));
675   }
676
677   /* cleanup */
678   pids_list_free(pids_list_before);
679   pids_list_free(pids_list_after);
680   pids_list_free(new_pids);
681   pids_list_free(lost_pids);
682
683   return 0;
684 }
685
686 DEF_TEST(rdt_pid_list_diff__nothing_changed) {
687   /* setup */
688   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
689   pids_list_t *pids_list_before = NULL;
690   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) {
691     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
692   }
693
694   pids_list_t *new_pids = NULL;
695   size_t new_pids_count = 0;
696   pids_list_t *lost_pids = NULL;
697   size_t lost_pids_count = 0;
698
699   /* check */
700   int result = rdt_pid_list_diff(pids_list_before, pids_list_before, &new_pids,
701                                  &new_pids_count, &lost_pids, &lost_pids_count);
702   EXPECT_EQ_INT(0, result);
703   EXPECT_EQ_INT(0, lost_pids_count);
704   EXPECT_EQ_INT(0, new_pids_count);
705   OK(NULL == new_pids);
706   OK(NULL == lost_pids);
707
708   /* cleanup */
709   pids_list_free(pids_list_before);
710
711   return 0;
712 }
713
714 DEF_TEST(rdt_pid_list_diff__one_added) {
715   /* setup */
716   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
717   pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004,
718                               1005, 1006, 1007, 1008};
719   pids_list_t *pids_list_before = NULL;
720   pids_list_t *pids_list_after = NULL;
721   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i)
722     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
723
724   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i)
725     pids_list_add_pid(&pids_list_after, pids_array_after[i]);
726
727   pids_list_t *new_pids = NULL;
728   size_t new_pids_count = 0;
729   pids_list_t *lost_pids = NULL;
730   size_t lost_pids_count = 0;
731
732   /* check */
733   int result = rdt_pid_list_diff(pids_list_before, pids_list_after, &new_pids,
734                                  &new_pids_count, &lost_pids, &lost_pids_count);
735   EXPECT_EQ_INT(0, result);
736   EXPECT_EQ_INT(0, lost_pids_count);
737   EXPECT_EQ_INT(1, new_pids_count);
738   EXPECT_EQ_INT(1008, new_pids->pid);
739
740   /* cleanup */
741   pids_list_free(pids_list_before);
742   pids_list_free(pids_list_after);
743   pids_list_free(new_pids);
744
745   return 0;
746 }
747
748 DEF_TEST(rdt_pid_list_diff__one_removed) {
749   /* setup */
750   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004,
751                                1005, 1006, 1007, 1008};
752   pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
753   pids_list_t *pids_list_before = NULL;
754   pids_list_t *pids_list_after = NULL;
755   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i)
756     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
757
758   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i)
759     pids_list_add_pid(&pids_list_after, pids_array_after[i]);
760
761   pids_list_t *new_pids = NULL;
762   size_t new_pids_count = 0;
763   pids_list_t *lost_pids = NULL;
764   size_t lost_pids_count = 0;
765
766   /* check */
767   int result = rdt_pid_list_diff(pids_list_before, pids_list_after, &new_pids,
768                                  &new_pids_count, &lost_pids, &lost_pids_count);
769   EXPECT_EQ_INT(0, result);
770   EXPECT_EQ_INT(1, lost_pids_count);
771   EXPECT_EQ_INT(0, new_pids_count);
772   EXPECT_EQ_INT(1008, lost_pids->pid);
773
774   /* cleanup */
775   pids_list_free(pids_list_before);
776   pids_list_free(pids_list_after);
777   pids_list_free(lost_pids);
778
779   return 0;
780 }
781
782 int main(void) {
783   stub_procfs_teardown();
784   RUN_TEST(initialize_proc_pids__on_nullptr);
785   RUN_TEST(add_proc_pid__empty_list);
786   RUN_TEST(add_proc_pid__non_empty_list);
787   RUN_TEST(pids_list_to_array__non_empty_list);
788   RUN_TEST(pids_list_add_pids_list__non_empty_lists);
789   RUN_TEST(pids_list_add_pids_list__add_to_empty);
790   RUN_TEST(get_pid_number__valid_dir);
791   RUN_TEST(get_pid_number__invalid_dir_name);
792   RUN_TEST(read_proc_name__valid_name);
793   RUN_TEST(read_proc_name__invalid_name);
794   RUN_TEST(fetch_pids_for_procs__one_proc_many_pid);
795   RUN_TEST(fetch_pids_for_procs__many_proc_many_pid);
796   RUN_TEST(rdt_config_ngroups__one_process);
797   RUN_TEST(rdt_config_ngroups__two_groups);
798   RUN_TEST(rdt_config_ngroups__too_long_proc_name);
799   RUN_TEST(rdt_config_ngroups__duplicate_proc_name_between_groups);
800   RUN_TEST(rdt_config_ngroups__duplicate_proc_name_in_group);
801   RUN_TEST(rdt_config_ngroups__empty_group);
802   RUN_TEST(rdt_config_ngroups__empty_proc_name);
803   RUN_TEST(rdt_pid_list_diff__all_changed);
804   RUN_TEST(rdt_pid_list_diff__nothing_changed);
805   RUN_TEST(rdt_pid_list_diff__one_added);
806   RUN_TEST(rdt_pid_list_diff__one_removed);
807   stub_procfs_teardown();
808   END_TEST;
809 }
810
811 #else
812 /***************************************************************************
813  * PQOS v1.2 mocks
814  */
815 int pqos_mon_reset(void) { return 0; }
816 int pqos_mon_assoc_get(const unsigned lcore, pqos_rmid_t *rmid) { return 0; }
817 int pqos_mon_start(const unsigned num_cores, const unsigned *cores,
818                    const enum pqos_mon_event event, void *context,
819                    struct pqos_mon_data *group) {
820   return 0;
821 }
822 int pqos_mon_start_pid(const pid_t pids, const enum pqos_mon_event event,
823                        void *context, struct pqos_mon_data *group) {
824   return 0;
825 }
826 int pqos_mon_stop(struct pqos_mon_data *group) { return 0; }
827 int pqos_mon_poll(struct pqos_mon_data **groups, const unsigned num_groups) {
828   return 0;
829 }
830 int pqos_alloc_assoc_set(const unsigned lcore, const unsigned class_id) {
831   return 0;
832 }
833 int pqos_alloc_assoc_get(const unsigned lcore, unsigned *class_id) { return 0; }
834 int pqos_alloc_assoc_set_pid(const pid_t task, const unsigned class_id) {
835   return 0;
836 }
837 int pqos_alloc_assoc_get_pid(const pid_t task, unsigned *class_id) { return 0; }
838 int pqos_alloc_assign(const unsigned technology, const unsigned *core_array,
839                       const unsigned core_num, unsigned *class_id) {
840   return 0;
841 }
842 int pqos_alloc_release(const unsigned *core_array, const unsigned core_num) {
843   return 0;
844 }
845 int pqos_alloc_assign_pid(const unsigned technology, const pid_t *task_array,
846                           const unsigned task_num, unsigned *class_id) {
847   return 0;
848 }
849 int pqos_alloc_release_pid(const pid_t *task_array, const unsigned task_num) {
850   return 0;
851 }
852 int pqos_init(const struct pqos_config *config) { return 0; }
853 int pqos_fini(void) { return 0; }
854 int pqos_cap_get_type(const struct pqos_cap *cap, const enum pqos_cap_type type,
855                       const struct pqos_capability **cap_item) {
856   return 0;
857 }
858 int pqos_cap_get(const struct pqos_cap **cap, const struct pqos_cpuinfo **cpu) {
859   return 0;
860 }
861
862 DEF_TEST(pqos12_test_stub) {
863   EXPECT_EQ_INT(0, 0);
864   return 0;
865 }
866
867 int main(void) {
868   RUN_TEST(pqos12_test_stub);
869   END_TEST;
870 }
871 #endif