b7e6c3b2b0289b8845ac1cfa7b8b4146961c7d7f
[collectd.git] / src / utils_proc_pids_test.c
1 #include "testing.h"
2 #include "utils_proc_pids.c" /* sic */
3 #include <sys/stat.h>
4
5 /***************************************************************************
6  * helper functions
7  */
8
9 /*
10  * NAME
11  *   pids_list_get_element
12  *
13  * DESCRIPTION
14  *   Gets list element at index position. Assumes list was created by
15  *   pids_list_add_pid function.
16  *
17  * PARAMETERS
18  *   `list'      Pids list
19  *   `index'     Position of desired element relative to given list pointer.
20  *
21  * RETURN VALUE
22  *   Pointer to element at index position.
23  *   NULL if index exceeds list's length.
24  */
25 pids_list_t *pids_list_get_element(pids_list_t *list, const size_t index) {
26   assert(list);
27   size_t current = 0;
28   while (list != NULL && current != index) {
29     list = list->next;
30     current++;
31   }
32   return list;
33 }
34
35 typedef struct stub_proc_pid {
36   proc_comm_t comm;
37   pid_t pid;
38 } stub_proc_pid_t;
39
40 static const char *proc_fs = "/tmp/procfs_stub";
41
42 /*
43  * NAME
44  *   stub_procfs_setup
45  *
46  * DESCRIPTION
47  *   Prepares testing environment by creating temporary
48  *   PID/comm file structure.
49  *
50  * PARAMETERS
51  *   `proc_pids_array'          Array of stub_proc_pid_t structs. Represents
52  *                              which PIDs should hold given process name.
53  *   `proc_pids_array_length'   Element count of input array.
54  *
55  * RETURN VALUE
56  *   0 on success.
57  *   -1 on base dir creation error.
58  *   -2 on comm file creation error.
59  */
60 int stub_procfs_setup(const stub_proc_pid_t *proc_pids_array,
61                       const size_t proc_pids_array_length) {
62   if (mkdir(proc_fs, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
63     return -1;
64   char path[256];
65
66   for (size_t i = 0; i < proc_pids_array_length; ++i) {
67     memset(path, 0, sizeof(path));
68     snprintf(path, STATIC_ARRAY_SIZE(path), "%s/%d", proc_fs,
69              proc_pids_array[i].pid);
70     mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
71     strncat(path, "/comm", STATIC_ARRAY_SIZE(path) - strlen(path) - 1);
72
73     FILE *fp = fopen(path, "w");
74     if (!fp)
75       return -2;
76     fwrite(proc_pids_array[i].comm, sizeof(char),
77            strlen(proc_pids_array[i].comm), fp);
78     fclose(fp);
79   }
80   return 0;
81 }
82
83 /*
84  * NAME
85  *   stub_procfs_teardown
86  *
87  * DESCRIPTION
88  *   Clears testing environment: removes stub proc files.
89  *   NOTE - This function could be implemented by usage of nftw, but this
90  *   would require #define _XOPEN_SOURCE 500, which
91  *   messes up intel_rdt includes.
92  *
93  * RETURN VALUE
94  *   system command result
95  */
96 int stub_procfs_teardown() {
97   char cmd[256];
98   sstrncpy(cmd, "rm -rf ", STATIC_ARRAY_SIZE(cmd));
99   strncat(cmd, proc_fs, STATIC_ARRAY_SIZE(cmd) - strlen(cmd) - 1);
100   return system(cmd);
101 }
102
103 /* Max PID value. More info:
104  * http://web.archive.org/web/20111209081734/http://research.cs.wisc.edu/condor/condorg/linux_scalability.html
105  */
106 #define MAX_PID 4194304
107 #define MAX_PID_STR "4194304"
108
109 /***************************************************************************
110  * tests
111  */
112 DEF_TEST(initialize_proc_pids__on_nullptr) {
113   /* setup */
114   const char *procs_names_array[] = {"proc1", "proc2", "proc3"};
115   const size_t procs_names_array_size = STATIC_ARRAY_SIZE(procs_names_array);
116   proc_pids_t *proc_pids_array = NULL;
117
118   /* check */
119   int result = initialize_proc_pids(procs_names_array, procs_names_array_size,
120                                     &proc_pids_array);
121   EXPECT_EQ_INT(0, result);
122   for (size_t i = 0; i < procs_names_array_size; ++i)
123     EXPECT_EQ_STR(procs_names_array[i], proc_pids_array[i].proccess_name);
124
125   /* cleanup */
126   free(proc_pids_array);
127   return 0;
128 }
129
130 DEF_TEST(add_proc_pid__empty_list) {
131   /* setup */
132   proc_pids_t proc_pids_instance;
133   proc_pids_instance.pids = NULL;
134   pid_t pid = 1234;
135
136   /* check */
137   pids_list_add_pid(&proc_pids_instance.pids, pid);
138   pids_list_t *added = pids_list_get_element(proc_pids_instance.pids, 0);
139   EXPECT_EQ_INT(pid, added->pid);
140
141   /* cleanup */
142   pids_list_free(proc_pids_instance.pids);
143   return 0;
144 }
145
146 DEF_TEST(add_proc_pid__non_empty_list) {
147   /* setup */
148   proc_pids_t proc_pids_instance;
149   proc_pids_instance.pids = NULL;
150   pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
151
152   /* check */
153   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i)
154     pids_list_add_pid(&proc_pids_instance.pids, pids[i]);
155
156   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) {
157     pids_list_t *added = pids_list_get_element(proc_pids_instance.pids, i);
158     EXPECT_EQ_INT(pids[i], added->pid);
159   }
160
161   /* cleanup */
162   pids_list_free(proc_pids_instance.pids);
163   return 0;
164 }
165
166 DEF_TEST(pids_list_to_array__non_empty_list) {
167   /* setup */
168   pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
169   pids_list_t *pids_list = NULL;
170   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i)
171     pids_list_add_pid(&pids_list, pids[i]);
172
173   /* check */
174   pid_t target_array[STATIC_ARRAY_SIZE(pids)];
175   pids_list_to_array(target_array, pids_list, STATIC_ARRAY_SIZE(target_array));
176   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i)
177     EXPECT_EQ_INT(pids[i], target_array[i]);
178
179   /* cleanup */
180   pids_list_free(pids_list);
181   return 0;
182 }
183
184 DEF_TEST(pids_list_add_pids_list__non_empty_lists) {
185   /* setup */
186   pid_t pids_array_1[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
187   pid_t pids_array_2[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
188   pids_list_t *pids_list_1 = NULL;
189   pids_list_t *pids_list_2 = NULL;
190   size_t increase = 0;
191   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) {
192     pids_list_add_pid(&pids_list_1, pids_array_1[i]);
193     pids_list_add_pid(&pids_list_2, pids_array_2[i]);
194   }
195
196   /* check */
197   int result = pids_list_add_pids_list(&pids_list_1, pids_list_2, &increase);
198   EXPECT_EQ_INT(0, result);
199   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_2), increase);
200
201   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) {
202     EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_1[i]));
203     EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_2[i]));
204   }
205
206   /* setup */
207   pids_list_free(pids_list_1);
208   pids_list_free(pids_list_2);
209   return 0;
210 }
211
212 DEF_TEST(pids_list_add_pids_list__add_to_empty) {
213   /* setup */
214   pid_t pids_array[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
215   pids_list_t *pids_list_1 = NULL;
216   pids_list_t *pids_list_2 = NULL;
217   size_t increase = 0;
218   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i)
219     pids_list_add_pid(&pids_list_2, pids_array[i]);
220
221   /* check */
222   int result = pids_list_add_pids_list(&pids_list_1, pids_list_2, &increase);
223   EXPECT_EQ_INT(0, result);
224   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array), increase);
225
226   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i)
227     EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array[i]));
228
229   /* setup */
230   pids_list_free(pids_list_1);
231   pids_list_free(pids_list_2);
232   return 0;
233 }
234
235 DEF_TEST(get_pid_number__valid_dir) {
236   /* setup */
237   struct dirent d;
238   sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
239   d.d_type = DT_DIR;
240   pid_t pid = 0;
241
242   /* check */
243   int pid_conversion = get_pid_number(&d, &pid);
244
245   EXPECT_EQ_INT(0, pid_conversion);
246   EXPECT_EQ_INT(MAX_PID, pid);
247
248   /* cleanup */
249   return 0;
250 }
251
252 DEF_TEST(get_pid_number__invalid_dir_name) {
253   /* setup */
254   struct dirent d;
255   sstrncpy(d.d_name, "invalid", STATIC_ARRAY_SIZE(d.d_name));
256   d.d_type = DT_DIR;
257   pid_t pid = 0;
258
259   /* check */
260   int pid_conversion = get_pid_number(&d, &pid);
261
262   EXPECT_EQ_INT(-1, pid_conversion);
263   EXPECT_EQ_INT(0, pid);
264
265   /* cleanup */
266   return 0;
267 }
268
269 DEF_TEST(read_proc_name__valid_name) {
270   /* setup */
271   stub_proc_pid_t pp_stubs[] = {{"proc1", MAX_PID}};
272   stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
273   struct dirent d;
274   sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
275   d.d_type = DT_DIR;
276
277   /* check */
278   proc_comm_t comm;
279   int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm));
280
281   EXPECT_EQ_INT(strlen(pp_stubs[0].comm), read_result);
282   EXPECT_EQ_STR(pp_stubs[0].comm, comm);
283
284   /* cleanup */
285   stub_procfs_teardown();
286   return 0;
287 }
288
289 DEF_TEST(read_proc_name__invalid_name) {
290   /* setup */
291   struct dirent d;
292   sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
293   d.d_type = DT_DIR;
294
295   /* check */
296   proc_comm_t comm;
297   int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm));
298
299   EXPECT_EQ_INT(-1, read_result);
300
301   /* cleanup */
302   return 0;
303 }
304
305 DEF_TEST(fetch_pids_for_procs__one_proc_many_pid) {
306   /* setup */
307   const char *proc_names[] = {"proc1"};
308   stub_proc_pid_t pp_stubs[] = {{"proc1", 1007},
309                                 {"proc1", 1008},
310                                 {"proc1", 1009},
311                                 {"proc2", 1010},
312                                 {"proc3", 1011}};
313   stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
314   proc_pids_t *output = NULL;
315
316   /* check */
317   int result = fetch_pids_for_procs(proc_fs, proc_names,
318                                     STATIC_ARRAY_SIZE(proc_names), &output);
319   EXPECT_EQ_INT(0, result);
320
321   /* proc name check */
322   EXPECT_EQ_STR(proc_names[0], output[0].proccess_name);
323
324   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pp_stubs); ++i) {
325     if (0 == strcmp(pp_stubs[i].comm, proc_names[0]))
326       /* check if proc struct has correct pids */
327       EXPECT_EQ_INT(pids_list_contains_pid(output[0].pids, pp_stubs[i].pid), 1);
328     else
329       /* check if proc struct has no incorrect pids */
330       EXPECT_EQ_INT(pids_list_contains_pid(output[0].pids, pp_stubs[i].pid), 0);
331   }
332
333   /* cleanup */
334   for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i)
335     pids_list_free(output[i].pids);
336   free(output);
337   stub_procfs_teardown();
338   return 0;
339 }
340
341 DEF_TEST(fetch_pids_for_procs__many_proc_many_pid) {
342   /* setup */
343   const char *proc_names[] = {"proc1", "proc2", "proc3"};
344   stub_proc_pid_t pp_stubs[] = {
345       {"proc1", 1007}, {"proc1", 1008}, {"proc1", 1009}, {"proc2", 2007},
346       {"proc2", 2008}, {"proc2", 2009}, {"proc3", 3007}, {"proc3", 3008},
347       {"proc3", 3009}, {"proc4", 4007}, {"proc4", 4008}, {"proc4", 4009},
348       {"proc5", 5007}, {"proc5", 5008}, {"proc5", 5009}};
349   stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
350   proc_pids_t *output = NULL;
351
352   /* check */
353   int result = fetch_pids_for_procs(proc_fs, proc_names,
354                                     STATIC_ARRAY_SIZE(proc_names), &output);
355   EXPECT_EQ_INT(0, result);
356
357   for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) {
358
359     /* proc name check */
360     EXPECT_EQ_STR(proc_names[i], output[i].proccess_name);
361
362     for (size_t j = 0; j < STATIC_ARRAY_SIZE(pp_stubs); ++j) {
363       if (0 == strcmp(pp_stubs[j].comm, proc_names[i]))
364         /* check if proc struct has correct pids */
365         EXPECT_EQ_INT(pids_list_contains_pid(output[i].pids, pp_stubs[j].pid),
366                       1);
367       else
368         /* check if proc struct has no incorrect pids */
369         EXPECT_EQ_INT(pids_list_contains_pid(output[i].pids, pp_stubs[j].pid),
370                       0);
371     }
372   }
373
374   /* cleanup */
375   for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i)
376     pids_list_free(output[i].pids);
377   free(output);
378   stub_procfs_teardown();
379   return 0;
380 }
381
382 DEF_TEST(pids_list_diff__all_changed) {
383   /* setup */
384   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
385   pid_t pids_array_after[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
386   pids_list_t *pids_list_before = NULL;
387   pids_list_t *pids_list_after = NULL;
388   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i) {
389     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
390     pids_list_add_pid(&pids_list_after, pids_array_after[i]);
391   }
392
393   pids_list_t *new_pids = NULL;
394   size_t new_pids_count = 0;
395   pids_list_t *lost_pids = NULL;
396   size_t lost_pids_count = 0;
397
398   /* check */
399   int result = pids_list_diff(pids_list_before, pids_list_after, &new_pids,
400                               &new_pids_count, &lost_pids, &lost_pids_count);
401   EXPECT_EQ_INT(0, result);
402   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_before), lost_pids_count);
403   EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_after), new_pids_count);
404
405   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) {
406     EXPECT_EQ_INT(1, pids_list_contains_pid(new_pids, pids_array_after[i]));
407     EXPECT_EQ_INT(1, pids_list_contains_pid(lost_pids, pids_array_before[i]));
408   }
409
410   /* cleanup */
411   pids_list_free(pids_list_before);
412   pids_list_free(pids_list_after);
413   pids_list_free(new_pids);
414   pids_list_free(lost_pids);
415
416   return 0;
417 }
418
419 DEF_TEST(pids_list_diff__nothing_changed) {
420   /* setup */
421   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
422   pids_list_t *pids_list_before = NULL;
423   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) {
424     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
425   }
426
427   pids_list_t *new_pids = NULL;
428   size_t new_pids_count = 0;
429   pids_list_t *lost_pids = NULL;
430   size_t lost_pids_count = 0;
431
432   /* check */
433   int result = pids_list_diff(pids_list_before, pids_list_before, &new_pids,
434                               &new_pids_count, &lost_pids, &lost_pids_count);
435   EXPECT_EQ_INT(0, result);
436   EXPECT_EQ_INT(0, lost_pids_count);
437   EXPECT_EQ_INT(0, new_pids_count);
438   OK(NULL == new_pids);
439   OK(NULL == lost_pids);
440
441   /* cleanup */
442   pids_list_free(pids_list_before);
443
444   return 0;
445 }
446
447 DEF_TEST(pids_list_diff__one_added) {
448   /* setup */
449   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
450   pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004,
451                               1005, 1006, 1007, 1008};
452   pids_list_t *pids_list_before = NULL;
453   pids_list_t *pids_list_after = NULL;
454   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i)
455     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
456
457   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i)
458     pids_list_add_pid(&pids_list_after, pids_array_after[i]);
459
460   pids_list_t *new_pids = NULL;
461   size_t new_pids_count = 0;
462   pids_list_t *lost_pids = NULL;
463   size_t lost_pids_count = 0;
464
465   /* check */
466   int result = pids_list_diff(pids_list_before, pids_list_after, &new_pids,
467                               &new_pids_count, &lost_pids, &lost_pids_count);
468   EXPECT_EQ_INT(0, result);
469   EXPECT_EQ_INT(0, lost_pids_count);
470   EXPECT_EQ_INT(1, new_pids_count);
471   EXPECT_EQ_INT(1008, new_pids->pid);
472
473   /* cleanup */
474   pids_list_free(pids_list_before);
475   pids_list_free(pids_list_after);
476   pids_list_free(new_pids);
477
478   return 0;
479 }
480
481 DEF_TEST(pids_list_diff__one_removed) {
482   /* setup */
483   pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004,
484                                1005, 1006, 1007, 1008};
485   pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
486   pids_list_t *pids_list_before = NULL;
487   pids_list_t *pids_list_after = NULL;
488   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i)
489     pids_list_add_pid(&pids_list_before, pids_array_before[i]);
490
491   for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_after); ++i)
492     pids_list_add_pid(&pids_list_after, pids_array_after[i]);
493
494   pids_list_t *new_pids = NULL;
495   size_t new_pids_count = 0;
496   pids_list_t *lost_pids = NULL;
497   size_t lost_pids_count = 0;
498
499   /* check */
500   int result = pids_list_diff(pids_list_before, pids_list_after, &new_pids,
501                               &new_pids_count, &lost_pids, &lost_pids_count);
502   EXPECT_EQ_INT(0, result);
503   EXPECT_EQ_INT(1, lost_pids_count);
504   EXPECT_EQ_INT(0, new_pids_count);
505   EXPECT_EQ_INT(1008, lost_pids->pid);
506
507   /* cleanup */
508   pids_list_free(pids_list_before);
509   pids_list_free(pids_list_after);
510   pids_list_free(lost_pids);
511
512   return 0;
513 }
514
515 int main(void) {
516   stub_procfs_teardown();
517   RUN_TEST(initialize_proc_pids__on_nullptr);
518   RUN_TEST(add_proc_pid__empty_list);
519   RUN_TEST(add_proc_pid__non_empty_list);
520   RUN_TEST(pids_list_to_array__non_empty_list);
521   RUN_TEST(pids_list_add_pids_list__non_empty_lists);
522   RUN_TEST(pids_list_add_pids_list__add_to_empty);
523   RUN_TEST(get_pid_number__valid_dir);
524   RUN_TEST(get_pid_number__invalid_dir_name);
525   RUN_TEST(read_proc_name__valid_name);
526   RUN_TEST(read_proc_name__invalid_name);
527   RUN_TEST(fetch_pids_for_procs__one_proc_many_pid);
528   RUN_TEST(fetch_pids_for_procs__many_proc_many_pid);
529   RUN_TEST(pids_list_diff__all_changed);
530   RUN_TEST(pids_list_diff__nothing_changed);
531   RUN_TEST(pids_list_diff__one_added);
532   RUN_TEST(pids_list_diff__one_removed);
533   stub_procfs_teardown();
534   END_TEST;
535 }