master
c 779 lines 23.5 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "ebpf_unittest.h"
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
11 #include "libbpf_api/ebpf_library.h"
12 #include "ebpf.h"
13 #include "ebpf_socket.h"
14
15 extern uint32_t integration_with_collectors;
16 extern int running_on_kernel;
17 extern int isrh;
18 extern ebpf_module_t ebpf_modules[];
19 extern char *ebpf_algorithms[];
20
21 ebpf_module_t test_em;
22
23 static int tests_failed = 0;
24
25 #define EBPF_UT_ASSERT(test, msg) \
26 do { \
27 if (!(test)) { \
28 fprintf(stderr, ">>> FAILED: %s\n", msg); \
29 tests_failed++; \
30 } else { \
31 fprintf(stderr, ">>> PASSED: %s\n", msg); \
32 } \
33 } while (0)
34
35 /**
36 * Initialize structure
37 *
38 * Initialize structure used to run unittests
39 */
40 void ebpf_ut_initialize_structure(netdata_run_mode_t mode)
41 {
42 memset(&test_em, 0, sizeof(ebpf_module_t));
43 test_em.info.thread_name = strdupz("process");
44 test_em.info.config_name = test_em.info.thread_name;
45 test_em.kernels =
46 NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10 | NETDATA_V5_14;
47 test_em.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE;
48 test_em.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT;
49 test_em.mode = mode;
50 }
51
52 /**
53 * Clean UP Memory
54 *
55 * Clean up allocated data during unit test;
56 */
57 void ebpf_ut_cleanup_memory()
58 {
59 freez((void *)test_em.info.thread_name);
60 }
61
62 /**
63 * Load Binary
64 *
65 * Test load of legacy eBPF programs.
66 *
67 * @return It returns 0 on success and -1 otherwise.
68 */
69 static int ebpf_ut_load_binary()
70 {
71 test_em.probe_links = ebpf_load_program(ebpf_plugin_dir, &test_em, running_on_kernel, isrh, &test_em.objects);
72 if (!test_em.probe_links)
73 return -1;
74
75 ebpf_unload_legacy_code(test_em.objects, test_em.probe_links);
76
77 return 0;
78 }
79
80 /**
81 * Load Real Binary
82 *
83 * Load an existent binary inside plugin directory.
84 *
85 * @return It returns 0 on success and -1 otherwise.
86 */
87 int ebpf_ut_load_real_binary()
88 {
89 return ebpf_ut_load_binary();
90 }
91 /**
92 * Load fake Binary
93 *
94 * Try to load a binary not generated by netdata.
95 *
96 * @return It returns 0 on success and -1 otherwise. The success for this function means we could work properly with
97 * expected fails.
98 */
99 int ebpf_ut_load_fake_binary()
100 {
101 char *fake_name = strdupz("I_am_not_here");
102 if (!fake_name)
103 return -1;
104
105 const char *original = test_em.info.thread_name;
106 test_em.info.thread_name = fake_name;
107
108 int ret = ebpf_ut_load_binary();
109
110 freez(fake_name);
111 test_em.info.thread_name = original;
112
113 return !ret;
114 }
115
116 /**
117 * Test write_chart_dimension
118 *
119 * Tests the write_chart_dimension function to ensure it correctly
120 * formats dimension output for charting.
121 */
122 static void test_write_chart_dimension(void)
123 {
124 fprintf(stderr, "\n=== Testing write_chart_dimension ===\n");
125
126 fprintf(stderr, "--- Expected output: SET dimension_name = 12345 ---\n");
127 fprintf(stderr, "--- Actual output: ");
128 write_chart_dimension("dimension_name", 12345);
129 fprintf(stderr, "---\n");
130 }
131
132 /**
133 * Test ebpf_write_global_dimension
134 *
135 * Tests the ebpf_write_global_dimension function to ensure it correctly
136 * formats global dimension output for charting.
137 */
138 static void test_ebpf_write_global_dimension(void)
139 {
140 fprintf(stderr, "\n=== Testing ebpf_write_global_dimension ===\n");
141
142 fprintf(stderr, "--- Expected output: DIMENSION name id algorithm ---\n");
143 fprintf(stderr, "--- Actual output: ");
144 ebpf_write_global_dimension("name", "id", "algorithm");
145 fprintf(stderr, "---\n");
146 }
147
148 /**
149 * Test ebpf_write_chart_cmd
150 *
151 * Tests the ebpf_write_chart_cmd function to ensure it correctly
152 * formats chart command output.
153 */
154 static void test_ebpf_write_chart_cmd(void)
155 {
156 fprintf(stderr, "\n=== Testing ebpf_write_chart_cmd ===\n");
157
158 fprintf(stderr, "--- Testing chart command output ---\n");
159 ebpf_write_chart_cmd("type", "id", "_suffix", "title", "units", "family", "charttype", "context", 100, 1, "module");
160 }
161
162 /**
163 * Test ebpf_write_chart_obsolete
164 *
165 * Tests the ebpf_write_chart_obsolete function to ensure it correctly
166 * formats obsolete chart output.
167 */
168 static void test_ebpf_write_chart_obsolete(void)
169 {
170 fprintf(stderr, "\n=== Testing ebpf_write_chart_obsolete ===\n");
171
172 fprintf(stderr, "--- Testing obsolete chart output ---\n");
173 ebpf_write_chart_obsolete("type", "id", "_suffix", "title", "units", "family", "charttype", "context", 100, 1);
174 }
175
176 /**
177 * Test ebpf_clean_ip_structure
178 *
179 * Tests the ebpf_clean_ip_structure function to ensure it correctly
180 * frees allocated IP list structures and clears the list pointer.
181 */
182 static void test_ebpf_clean_ip_structure(void)
183 {
184 fprintf(stderr, "\n=== Testing ebpf_clean_ip_structure ===\n");
185
186 ebpf_network_viewer_ip_list_t *list = NULL;
187 ebpf_network_viewer_ip_list_t *item1, *item2;
188
189 item1 = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
190 item1->value = strdupz("192.168.1.1");
191 item1->ver = AF_INET;
192 item1->next = NULL;
193
194 item2 = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
195 item2->value = strdupz("10.0.0.1");
196 item2->ver = AF_INET;
197 item2->next = NULL;
198
199 list = item1;
200 item1->next = item2;
201
202 EBPF_UT_ASSERT(list != NULL, "List should not be NULL before cleaning");
203 EBPF_UT_ASSERT(list->next != NULL, "List should have two items before cleaning");
204
205 ebpf_clean_ip_structure(&list);
206
207 EBPF_UT_ASSERT(list == NULL, "List should be NULL after cleaning");
208 }
209
210 /**
211 * Test ebpf_clean_port_structure
212 *
213 * Tests the ebpf_clean_port_structure function to ensure it correctly
214 * frees allocated port list structures and clears the list pointer.
215 */
216 static void test_ebpf_clean_port_structure(void)
217 {
218 fprintf(stderr, "\n=== Testing ebpf_clean_port_structure ===\n");
219
220 ebpf_network_viewer_port_list_t *list = NULL;
221 ebpf_network_viewer_port_list_t *item1, *item2;
222
223 item1 = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
224 item1->value = strdupz("80");
225 item1->first = htons(80);
226 item1->last = htons(80);
227 item1->next = NULL;
228
229 item2 = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
230 item2->value = strdupz("443");
231 item2->first = htons(443);
232 item2->last = htons(443);
233 item2->next = NULL;
234
235 list = item1;
236 item1->next = item2;
237
238 EBPF_UT_ASSERT(list != NULL, "Port list should not be NULL before cleaning");
239 EBPF_UT_ASSERT(list->next != NULL, "Port list should have two items before cleaning");
240
241 ebpf_clean_port_structure(&list);
242
243 EBPF_UT_ASSERT(list == NULL, "Port list should be NULL after cleaning");
244 }
245
246 /**
247 * Test ebpf_how_to_load
248 *
249 * Tests the ebpf_how_to_load function to ensure it correctly parses
250 * load mode strings and sets the appropriate thread mode.
251 */
252 static void test_ebpf_how_to_load(void)
253 {
254 fprintf(stderr, "\n=== Testing ebpf_how_to_load ===\n");
255
256 ebpf_set_thread_mode(MODE_ENTRY);
257 EBPF_UT_ASSERT(ebpf_modules[0].mode == MODE_ENTRY, "Initial mode should be MODE_ENTRY");
258
259 ebpf_how_to_load("return");
260 EBPF_UT_ASSERT(ebpf_modules[0].mode == MODE_RETURN, "Mode should be MODE_RETURN after 'return'");
261
262 ebpf_how_to_load("entry");
263 EBPF_UT_ASSERT(ebpf_modules[0].mode == MODE_ENTRY, "Mode should be MODE_ENTRY after 'entry'");
264
265 ebpf_how_to_load("default");
266 EBPF_UT_ASSERT(ebpf_modules[0].mode == MODE_ENTRY, "Mode should be MODE_ENTRY after 'default'");
267
268 ebpf_how_to_load("invalid_mode");
269 EBPF_UT_ASSERT(ebpf_modules[0].mode == MODE_ENTRY, "Mode should remain MODE_ENTRY after invalid input");
270 }
271
272 /**
273 * Test ebpf_set_apps_mode
274 *
275 * Tests the ebpf_set_apps_mode function to ensure it correctly sets
276 * the apps integration mode for all modules.
277 */
278 static void test_ebpf_set_apps_mode(void)
279 {
280 fprintf(stderr, "\n=== Testing ebpf_set_apps_mode ===\n");
281
282 ebpf_set_apps_mode(NETDATA_EBPF_APPS_FLAG_YES);
283 EBPF_UT_ASSERT(
284 ebpf_modules[0].apps_charts == NETDATA_EBPF_APPS_FLAG_YES,
285 "Apps mode should be set to NETDATA_EBPF_APPS_FLAG_YES");
286
287 ebpf_set_apps_mode(NETDATA_EBPF_APPS_FLAG_NO);
288 EBPF_UT_ASSERT(
289 ebpf_modules[0].apps_charts == NETDATA_EBPF_APPS_FLAG_NO,
290 "Apps mode should be set to NETDATA_EBPF_APPS_FLAG_NO");
291 }
292
293 /**
294 * Test ebpf_set_thread_mode
295 *
296 * Tests the ebpf_set_thread_mode function to ensure it correctly sets
297 * the run mode for all eBPF modules.
298 */
299 static void test_ebpf_set_thread_mode(void)
300 {
301 fprintf(stderr, "\n=== Testing ebpf_set_thread_mode ===\n");
302
303 ebpf_set_thread_mode(MODE_RETURN);
304 EBPF_UT_ASSERT(ebpf_modules[0].mode == MODE_RETURN, "Thread mode should be MODE_RETURN");
305
306 ebpf_set_thread_mode(MODE_ENTRY);
307 EBPF_UT_ASSERT(ebpf_modules[0].mode == MODE_ENTRY, "Thread mode should be MODE_ENTRY");
308 }
309
310 /**
311 * Test ebpf_set_ipc_value
312 *
313 * Tests the ebpf_set_ipc_value function to ensure it correctly parses
314 * integration strings and sets the appropriate IPC integration mode.
315 */
316 static void test_ebpf_set_ipc_value(void)
317 {
318 fprintf(stderr, "\n=== Testing ebpf_set_ipc_value ===\n");
319
320 ebpf_set_ipc_value("shm");
321 EBPF_UT_ASSERT(
322 integration_with_collectors == NETDATA_EBPF_INTEGRATION_SHM,
323 "Integration should be NETDATA_EBPF_INTEGRATION_SHM");
324
325 ebpf_set_ipc_value("socket");
326 EBPF_UT_ASSERT(
327 integration_with_collectors == NETDATA_EBPF_INTEGRATION_SOCKET,
328 "Integration should be NETDATA_EBPF_INTEGRATION_SOCKET");
329
330 ebpf_set_ipc_value("disabled");
331 EBPF_UT_ASSERT(
332 integration_with_collectors == NETDATA_EBPF_INTEGRATION_DISABLED,
333 "Integration should be NETDATA_EBPF_INTEGRATION_DISABLED");
334
335 ebpf_set_ipc_value("invalid");
336 EBPF_UT_ASSERT(
337 integration_with_collectors == NETDATA_EBPF_INTEGRATION_DISABLED,
338 "Integration should be DISABLED for invalid input");
339 }
340
341 /**
342 * Test disable_all_global_charts
343 *
344 * Tests the disable_all_global_charts function to ensure it correctly
345 * disables all global charts across all modules.
346 */
347 static void test_disable_all_global_charts(void)
348 {
349 fprintf(stderr, "\n=== Testing disable_all_global_charts ===\n");
350
351 ebpf_modules[0].enabled = NETDATA_THREAD_EBPF_RUNNING;
352 ebpf_modules[0].global_charts = 1;
353
354 disable_all_global_charts();
355
356 EBPF_UT_ASSERT(
357 ebpf_modules[0].enabled == NETDATA_THREAD_EBPF_NOT_RUNNING,
358 "Module should be disabled after disable_all_global_charts");
359 EBPF_UT_ASSERT(ebpf_modules[0].global_charts == 0, "Global charts should be disabled");
360 }
361
362 /**
363 * Test ebpf_disable_cgroups
364 *
365 * Tests the ebpf_disable_cgroups function to ensure it correctly
366 * disables cgroup charts across all modules.
367 */
368 static void test_ebpf_disable_cgroups(void)
369 {
370 fprintf(stderr, "\n=== Testing ebpf_disable_cgroups ===\n");
371
372 ebpf_modules[0].cgroup_charts = 1;
373
374 ebpf_disable_cgroups();
375
376 EBPF_UT_ASSERT(ebpf_modules[0].cgroup_charts == 0, "Cgroup charts should be disabled");
377 }
378
379 /**
380 * Test ebpf_one_dimension_write_charts
381 *
382 * Tests the ebpf_one_dimension_write_charts function to ensure it correctly
383 * formats single dimension chart output.
384 */
385 static void test_ebpf_one_dimension_write_charts(void)
386 {
387 fprintf(stderr, "\n=== Testing ebpf_one_dimension_write_charts ===\n");
388
389 fprintf(stderr, "--- Testing single dimension chart output ---\n");
390 ebpf_one_dimension_write_charts("family", "chart", "dimension", 42);
391 }
392
393 /**
394 * Test write_io_chart
395 *
396 * Tests the write_io_chart function to ensure it correctly formats
397 * I/O chart output with read and write dimensions.
398 */
399 static void test_write_io_chart(void)
400 {
401 fprintf(stderr, "\n=== Testing write_io_chart ===\n");
402
403 fprintf(stderr, "--- Testing IO chart output ---\n");
404 write_io_chart("chart", "family", "write_dim", 100, "read_dim", 200);
405 }
406
407 /**
408 * Test write_histogram_chart
409 *
410 * Tests the write_histogram_chart function to ensure it correctly formats
411 * histogram chart output with multiple dimensions.
412 */
413 static void test_write_histogram_chart(void)
414 {
415 fprintf(stderr, "\n=== Testing write_histogram_chart ===\n");
416
417 uint64_t hist[4] = {10, 20, 30, 40};
418 char *dims[4] = {"bucket1", "bucket2", "bucket3", "bucket4"};
419
420 fprintf(stderr, "--- Testing histogram chart output ---\n");
421 write_histogram_chart("family", "histogram", hist, dims, 4);
422 }
423
424 /**
425 * Test ebpf_global_labels
426 *
427 * Tests the ebpf_global_labels function to ensure it correctly sets up
428 * syscall labels and creates proper linked lists.
429 */
430 static void test_ebpf_global_labels(void)
431 {
432 fprintf(stderr, "\n=== Testing ebpf_global_labels ===\n");
433
434 netdata_syscall_stat_t is[3];
435 netdata_publish_syscall_t pio[3];
436 char *dim[3] = {"dim1", "dim2", "dim3"};
437 char *name[3] = {"name1", "name2", "name3"};
438 int algorithm[3] = {0, 0, 0};
439
440 memset(is, 0, sizeof(is));
441 memset(pio, 0, sizeof(pio));
442
443 ebpf_global_labels(is, pio, dim, name, algorithm, 3);
444
445 EBPF_UT_ASSERT(is[0].next == &is[1], "is[0].next should point to is[1]");
446 EBPF_UT_ASSERT(is[1].next == &is[2], "is[1].next should point to is[2]");
447 EBPF_UT_ASSERT(is[2].next == NULL, "is[2].next should be NULL");
448
449 EBPF_UT_ASSERT(pio[0].dimension == dim[0], "pio[0].dimension should be dim[0]");
450 EBPF_UT_ASSERT(pio[1].dimension == dim[1], "pio[1].dimension should be dim[1]");
451 EBPF_UT_ASSERT(pio[2].dimension == dim[2], "pio[2].dimension should be dim[2]");
452 }
453
454 /**
455 * Test ebpf_parse_ports basic
456 *
457 * Tests the ebpf_parse_ports function with basic port numbers
458 * to ensure it correctly parses and creates port list entries.
459 */
460 static void test_ebpf_parse_ports_basic(void)
461 {
462 fprintf(stderr, "\n=== Testing ebpf_parse_ports (basic) ===\n");
463
464 network_viewer_opt.included_port = NULL;
465 network_viewer_opt.excluded_port = NULL;
466
467 ebpf_parse_ports("80 443");
468
469 EBPF_UT_ASSERT(network_viewer_opt.included_port != NULL, "Port list should not be NULL after parsing '80 443'");
470
471 ebpf_clean_port_structure(&network_viewer_opt.included_port);
472 network_viewer_opt.included_port = NULL;
473 }
474
475 /**
476 * Test ebpf_parse_ports with range
477 *
478 * Tests the ebpf_parse_ports function with port ranges
479 * to ensure it correctly parses and creates port range entries.
480 */
481 static void test_ebpf_parse_ports_with_range(void)
482 {
483 fprintf(stderr, "\n=== Testing ebpf_parse_ports with range ===\n");
484
485 network_viewer_opt.included_port = NULL;
486
487 ebpf_parse_ports("8000-9000");
488
489 EBPF_UT_ASSERT(network_viewer_opt.included_port != NULL, "Port list should not be NULL after parsing range");
490
491 if (network_viewer_opt.included_port) {
492 uint16_t first = ntohs(network_viewer_opt.included_port->first);
493 uint16_t last = ntohs(network_viewer_opt.included_port->last);
494 EBPF_UT_ASSERT(first == 8000, "First port should be 8000");
495 EBPF_UT_ASSERT(last == 9000, "Last port should be 9000");
496 }
497
498 ebpf_clean_port_structure(&network_viewer_opt.included_port);
499 network_viewer_opt.included_port = NULL;
500 }
501
502 /**
503 * Test ebpf_parse_ips_unsafe basic
504 *
505 * Tests the ebpf_parse_ips_unsafe function with basic IPv4 addresses
506 * to ensure it correctly parses and creates IP list entries.
507 */
508 static void test_ebpf_parse_ips_basic(void)
509 {
510 fprintf(stderr, "\n=== Testing ebpf_parse_ips_unsafe (basic) ===\n");
511
512 network_viewer_opt.included_ips = NULL;
513
514 ebpf_parse_ips_unsafe("192.168.1.1");
515
516 EBPF_UT_ASSERT(network_viewer_opt.included_ips != NULL, "IP list should not be NULL after parsing IP");
517
518 if (network_viewer_opt.included_ips) {
519 EBPF_UT_ASSERT(network_viewer_opt.included_ips->ver == AF_INET, "IP should be IPv4");
520 }
521
522 ebpf_clean_ip_structure(&network_viewer_opt.included_ips);
523 network_viewer_opt.included_ips = NULL;
524 }
525
526 /**
527 * Test ebpf_parse_ips_unsafe with CIDR
528 *
529 * Tests the ebpf_parse_ips_unsafe function with CIDR notation
530 * to ensure it correctly parses and creates IP range entries.
531 */
532 static void test_ebpf_parse_ips_with_cidr(void)
533 {
534 fprintf(stderr, "\n=== Testing ebpf_parse_ips_unsafe with CIDR ===\n");
535
536 network_viewer_opt.included_ips = NULL;
537
538 ebpf_parse_ips_unsafe("192.168.0.0/24");
539
540 EBPF_UT_ASSERT(network_viewer_opt.included_ips != NULL, "IP list should not be NULL after parsing CIDR");
541
542 ebpf_clean_ip_structure(&network_viewer_opt.included_ips);
543 network_viewer_opt.included_ips = NULL;
544 }
545
546 /**
547 * Test ebpf_print_help
548 *
549 * Tests the ebpf_print_help function to ensure it correctly
550 * outputs help information to stderr.
551 */
552 static void test_ebpf_print_help(void)
553 {
554 fprintf(stderr, "\n=== Testing ebpf_print_help ===\n");
555
556 fprintf(stderr, "--- Help output start ---\n");
557 ebpf_print_help();
558 fprintf(stderr, "--- Help output end ---\n");
559 }
560
561 /**
562 * Test write_count_chart
563 *
564 * Tests the write_count_chart function to ensure it correctly
565 * formats count chart output with syscall data.
566 */
567 static void test_write_count_chart(void)
568 {
569 fprintf(stderr, "\n=== Testing write_count_chart ===\n");
570
571 netdata_publish_syscall_t publish[2];
572 memset(publish, 0, sizeof(publish));
573
574 publish[0].name = strdupz("call1");
575 publish[0].ncall = 100;
576 publish[0].next = &publish[1];
577
578 publish[1].name = strdupz("call2");
579 publish[1].ncall = 200;
580 publish[1].next = NULL;
581
582 fprintf(stderr, "--- Count chart output ---\n");
583 write_count_chart("chart", "family", publish, 2);
584
585 freez(publish[0].name);
586 freez(publish[1].name);
587 }
588
589 /**
590 * Test write_err_chart
591 *
592 * Tests the write_err_chart function to ensure it correctly
593 * formats error chart output with syscall error data.
594 */
595 static void test_write_err_chart(void)
596 {
597 fprintf(stderr, "\n=== Testing write_err_chart ===\n");
598
599 netdata_publish_syscall_t publish[2];
600 memset(publish, 0, sizeof(publish));
601
602 publish[0].name = strdupz("err1");
603 publish[0].nerr = 5;
604 publish[0].next = &publish[1];
605
606 publish[1].name = strdupz("err2");
607 publish[1].nerr = 10;
608 publish[1].next = NULL;
609
610 fprintf(stderr, "--- Error chart output ---\n");
611 write_err_chart("chart", "family", publish, 2);
612
613 freez(publish[0].name);
614 freez(publish[1].name);
615 }
616
617 /**
618 * Test ebpf_create_global_dimension
619 *
620 * Tests the ebpf_create_global_dimension function to ensure it correctly
621 * creates global dimension entries from a linked list.
622 */
623 static void test_ebpf_create_global_dimension(void)
624 {
625 fprintf(stderr, "\n=== Testing ebpf_create_global_dimension ===\n");
626
627 netdata_publish_syscall_t publish[3];
628 memset(publish, 0, sizeof(publish));
629
630 publish[0].name = strdupz("dim1");
631 publish[0].dimension = strdupz("dim1_id");
632 publish[0].algorithm = "absolute";
633 publish[0].next = &publish[1];
634
635 publish[1].name = strdupz("dim2");
636 publish[1].dimension = strdupz("dim2_id");
637 publish[1].algorithm = "absolute";
638 publish[1].next = &publish[2];
639
640 publish[2].name = strdupz("dim3");
641 publish[2].dimension = strdupz("dim3_id");
642 publish[2].algorithm = "absolute";
643 publish[2].next = NULL;
644
645 fprintf(stderr, "--- Global dimension output ---\n");
646 ebpf_create_global_dimension(publish, 3);
647
648 freez(publish[0].name);
649 freez(publish[0].dimension);
650 freez(publish[1].name);
651 freez(publish[1].dimension);
652 freez(publish[2].name);
653 freez(publish[2].dimension);
654 }
655
656 /**
657 * Test ebpf_enable_specific_chart
658 *
659 * Tests the ebpf_enable_specific_chart function to ensure it correctly
660 * enables specific charts with proper flags.
661 */
662 static void test_ebpf_enable_specific_chart(void)
663 {
664 fprintf(stderr, "\n=== Testing ebpf_enable_specific_chart ===\n");
665
666 ebpf_module_t test_module;
667 memset(&test_module, 0, sizeof(test_module));
668
669 ebpf_enable_specific_chart(&test_module, 0);
670
671 EBPF_UT_ASSERT(test_module.enabled == NETDATA_THREAD_EBPF_RUNNING, "Module should be enabled");
672 EBPF_UT_ASSERT(test_module.global_charts == CONFIG_BOOLEAN_YES, "Global charts should be enabled");
673 EBPF_UT_ASSERT(
674 test_module.cgroup_charts == CONFIG_BOOLEAN_YES, "Cgroup charts should be enabled when disable_cgroup is 0");
675
676 memset(&test_module, 0, sizeof(test_module));
677 ebpf_enable_specific_chart(&test_module, 1);
678
679 EBPF_UT_ASSERT(test_module.cgroup_charts == 0, "Cgroup charts should be disabled when disable_cgroup is 1");
680 }
681
682 /**
683 * Test ebpf_enable_chart
684 *
685 * Tests the ebpf_enable_chart function to ensure it correctly
686 * enables charts by index.
687 */
688 static void test_ebpf_enable_chart(void)
689 {
690 fprintf(stderr, "\n=== Testing ebpf_enable_chart ===\n");
691
692 ebpf_modules[0].enabled = NETDATA_THREAD_EBPF_NOT_RUNNING;
693
694 ebpf_enable_chart(0, 0);
695
696 EBPF_UT_ASSERT(ebpf_modules[0].enabled == NETDATA_THREAD_EBPF_RUNNING, "Chart at index 0 should be enabled");
697 }
698
699 /**
700 * Test parse_network_viewer_section with NULL
701 *
702 * Tests the parse_network_viewer_section function with empty config
703 * to ensure it sets appropriate default values.
704 */
705 static void test_parse_network_viewer_section_null(void)
706 {
707 fprintf(stderr, "\n=== Testing parse_network_viewer_section (NULL) ===\n");
708
709 struct config cfg;
710 memset(&cfg, 0, sizeof(cfg));
711
712 parse_network_viewer_section(&cfg);
713
714 EBPF_UT_ASSERT(
715 network_viewer_opt.hostname_resolution_enabled == CONFIG_BOOLEAN_NO,
716 "Hostname resolution should be disabled by default");
717 }
718
719 /**
720 * Test ebpf_load_collector_config
721 *
722 * Tests the ebpf_load_collector_config function with non-existent path
723 * to ensure it handles errors correctly.
724 */
725 static void test_ebpf_load_collector_config(void)
726 {
727 fprintf(stderr, "\n=== Testing ebpf_load_collector_config ===\n");
728
729 int disable_cgroups = 0;
730 int result = ebpf_load_collector_config("/tmp", &disable_cgroups, 1);
731
732 EBPF_UT_ASSERT(result == -1, "Should return -1 for non-existent config path");
733 }
734
735 void ebpf_library_run_unittests(void)
736 {
737 fprintf(stderr, "\n");
738 fprintf(stderr, "===========================================\n");
739 fprintf(stderr, " EBPF Library Unit Tests\n");
740 fprintf(stderr, "===========================================\n");
741
742 test_write_chart_dimension();
743 test_ebpf_write_global_dimension();
744 test_ebpf_write_chart_cmd();
745 test_ebpf_write_chart_obsolete();
746 test_ebpf_clean_ip_structure();
747 test_ebpf_clean_port_structure();
748 test_ebpf_how_to_load();
749 test_ebpf_set_apps_mode();
750 test_ebpf_set_thread_mode();
751 test_ebpf_set_ipc_value();
752 test_disable_all_global_charts();
753 test_ebpf_disable_cgroups();
754 test_ebpf_one_dimension_write_charts();
755 test_write_io_chart();
756 test_write_histogram_chart();
757 test_ebpf_global_labels();
758 test_ebpf_parse_ports_basic();
759 test_ebpf_parse_ports_with_range();
760 test_ebpf_parse_ips_basic();
761 test_ebpf_parse_ips_with_cidr();
762 test_ebpf_print_help();
763 test_write_count_chart();
764 test_write_err_chart();
765 test_ebpf_create_global_dimension();
766 test_ebpf_enable_specific_chart();
767 test_ebpf_enable_chart();
768 test_parse_network_viewer_section_null();
769 test_ebpf_load_collector_config();
770
771 fprintf(stderr, "\n");
772 fprintf(stderr, "===========================================\n");
773 if (tests_failed == 0) {
774 fprintf(stderr, " All tests PASSED\n");
775 } else {
776 fprintf(stderr, " %d tests FAILED\n", tests_failed);
777 }
778 fprintf(stderr, "===========================================\n");
779 }