testapp: gen-syscall-events: use dynamic paths provided via args
[lttng-tools.git] / tests / regression / tools / notification / notification.c
1 /*
2 * notification.c
3 *
4 * Tests suite for LTTng notification API
5 *
6 * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
7 *
8 * SPDX-License-Identifier: MIT
9 *
10 */
11
12 #include <assert.h>
13 #include <math.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <inttypes.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <poll.h>
25
26 #include <common/compat/errno.h>
27 #include <lttng/action/action.h>
28 #include <lttng/action/notify.h>
29 #include <lttng/condition/buffer-usage.h>
30 #include <lttng/condition/condition.h>
31 #include <lttng/condition/evaluation.h>
32 #include <lttng/condition/event-rule.h>
33 #include <lttng/domain.h>
34 #include <lttng/endpoint.h>
35 #include <lttng/event-rule/kprobe.h>
36 #include <lttng/event-rule/tracepoint.h>
37 #include <lttng/kernel-probe.h>
38 #include <lttng/lttng-error.h>
39 #include <lttng/lttng.h>
40 #include <lttng/notification/channel.h>
41 #include <lttng/notification/notification.h>
42 #include <lttng/trigger/trigger.h>
43
44 #include <tap/tap.h>
45
46 int nb_args = 0;
47 int named_pipe_args_start = 0;
48 pid_t app_pid = 0;
49 const char *app_state_file = NULL;
50
51 static
52 void wait_on_file(const char *path, bool file_exist)
53 {
54 if (!path) {
55 return;
56 }
57 for (;;) {
58 int ret;
59 struct stat buf;
60
61 ret = stat(path, &buf);
62 if (ret == -1 && errno == ENOENT) {
63 if (file_exist) {
64 /*
65 * The file does not exist. wait a bit and
66 * continue looping until it does.
67 */
68 (void) poll(NULL, 0, 10);
69 continue;
70 }
71
72 /*
73 * File does not exist and the exit condition we want.
74 * Break from the loop and return.
75 */
76 break;
77 }
78 if (ret) {
79 perror("stat");
80 exit(EXIT_FAILURE);
81 }
82 /*
83 * stat() returned 0, so the file exists. break now only if
84 * that's the exit condition we want.
85 */
86 if (file_exist) {
87 break;
88 }
89 }
90 }
91
92 static
93 int write_pipe(const char *path, uint8_t data)
94 {
95 int ret = 0;
96 int fd = 0;
97
98 fd = open(path, O_WRONLY | O_NONBLOCK);
99 if (fd < 0) {
100 perror("Could not open consumer control named pipe");
101 goto end;
102 }
103
104 ret = write(fd, &data , sizeof(data));
105 if (ret < 1) {
106 perror("Named pipe write failed");
107 if (close(fd)) {
108 perror("Named pipe close failed");
109 }
110 ret = -1;
111 goto end;
112 }
113
114 ret = close(fd);
115 if (ret < 0) {
116 perror("Name pipe closing failed");
117 ret = -1;
118 goto end;
119 }
120 end:
121 return ret;
122 }
123
124 static
125 int stop_consumer(const char **argv)
126 {
127 int ret = 0, i;
128
129 for (i = named_pipe_args_start; i < nb_args; i++) {
130 ret = write_pipe(argv[i], 49);
131 }
132 return ret;
133 }
134
135 static
136 int resume_consumer(const char **argv)
137 {
138 int ret = 0, i;
139
140 for (i = named_pipe_args_start; i < nb_args; i++) {
141 ret = write_pipe(argv[i], 0);
142 }
143 return ret;
144 }
145
146 static
147 int suspend_application(void)
148 {
149 int ret;
150 struct stat buf;
151
152 if (!stat(app_state_file, &buf)) {
153 fail("App is already in a suspended state.");
154 ret = -1;
155 goto error;
156 }
157
158 /*
159 * Send SIGUSR1 to application instructing it to bypass tracepoint.
160 */
161 assert(app_pid > 1);
162
163 ret = kill(app_pid, SIGUSR1);
164 if (ret) {
165 fail("SIGUSR1 failed. errno %d", errno);
166 ret = -1;
167 goto error;
168 }
169
170 wait_on_file(app_state_file, true);
171
172 error:
173 return ret;
174
175 }
176
177 static
178 int resume_application(void)
179 {
180 int ret;
181 struct stat buf;
182
183 ret = stat(app_state_file, &buf);
184 if (ret == -1 && errno == ENOENT) {
185 fail("State file does not exist");
186 goto error;
187 }
188 if (ret) {
189 perror("stat");
190 goto error;
191 }
192
193 assert(app_pid > 1);
194
195 ret = kill(app_pid, SIGUSR1);
196 if (ret) {
197 fail("SIGUSR1 failed. errno %d", errno);
198 ret = -1;
199 goto error;
200 }
201
202 wait_on_file(app_state_file, false);
203
204 error:
205 return ret;
206
207 }
208
209
210 static
211 void test_triggers_buffer_usage_condition(const char *session_name,
212 const char *channel_name,
213 enum lttng_domain_type domain_type,
214 enum lttng_condition_type condition_type)
215 {
216 unsigned int test_vector_size = 5, i;
217 enum lttng_condition_status condition_status;
218 struct lttng_action *action;
219
220 /* Set-up */
221 action = lttng_action_notify_create();
222 if (!action) {
223 fail("Setup error on action creation");
224 goto end;
225 }
226
227 /* Test lttng_register_trigger with null value */
228 ok(lttng_register_trigger(NULL) == -LTTNG_ERR_INVALID, "Registering a NULL trigger fails as expected");
229
230 /* Test: register a trigger */
231
232 for (i = 0; i < pow(2,test_vector_size); i++) {
233 int loop_ret = 0;
234 char *test_tuple_string = NULL;
235 unsigned int mask_position = 0;
236 bool session_name_set = false;
237 bool channel_name_set = false;
238 bool threshold_ratio_set = false;
239 bool threshold_byte_set = false;
240 bool domain_type_set = false;
241
242 struct lttng_trigger *trigger = NULL;
243 struct lttng_condition *condition = NULL;
244
245 /* Create base condition */
246 switch (condition_type) {
247 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
248 condition = lttng_condition_buffer_usage_low_create();
249 break;
250 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
251 condition = lttng_condition_buffer_usage_high_create();
252 break;
253 default:
254 loop_ret = 1;
255 goto loop_end;
256 }
257
258 if (!condition) {
259 loop_ret = 1;
260 goto loop_end;
261
262 }
263
264 /* Prepare the condition for trigger registration test */
265
266 /* Set session name */
267 if ((1 << mask_position) & i) {
268 condition_status = lttng_condition_buffer_usage_set_session_name(
269 condition, session_name);
270 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
271 loop_ret = 1;
272 goto loop_end;
273 }
274 session_name_set = true;
275 }
276 mask_position++;
277
278 /* Set channel name */
279 if ((1 << mask_position) & i) {
280 condition_status = lttng_condition_buffer_usage_set_channel_name(
281 condition, channel_name);
282 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
283 loop_ret = 1;
284 goto loop_end;
285 }
286 channel_name_set = true;
287 }
288 mask_position++;
289
290 /* Set threshold ratio */
291 if ((1 << mask_position) & i) {
292 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
293 condition, 0.0);
294 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
295 loop_ret = 1;
296 goto loop_end;
297 }
298 threshold_ratio_set = true;
299 }
300 mask_position++;
301
302 /* Set threshold byte */
303 if ((1 << mask_position) & i) {
304 condition_status = lttng_condition_buffer_usage_set_threshold(
305 condition, 0);
306 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
307 loop_ret = 1;
308 goto loop_end;
309 }
310 threshold_byte_set = true;
311 }
312 mask_position++;
313
314 /* Set domain type */
315 if ((1 << mask_position) & i) {
316 condition_status = lttng_condition_buffer_usage_set_domain_type(
317 condition, LTTNG_DOMAIN_UST);
318 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
319 loop_ret = 1;
320 goto loop_end;
321 }
322 domain_type_set = true;
323 }
324
325 /* Safety check */
326 if (mask_position != test_vector_size -1) {
327 assert("Logic error for test vector generation");
328 }
329
330 loop_ret = asprintf(&test_tuple_string, "session name %s, channel name %s, threshold ratio %s, threshold byte %s, domain type %s",
331 session_name_set ? "set" : "unset",
332 channel_name_set ? "set" : "unset",
333 threshold_ratio_set ? "set" : "unset",
334 threshold_byte_set ? "set" : "unset",
335 domain_type_set? "set" : "unset");
336 if (!test_tuple_string || loop_ret < 0) {
337 loop_ret = 1;
338 goto loop_end;
339 }
340
341 /* Create trigger */
342 trigger = lttng_trigger_create(condition, action);
343 if (!trigger) {
344 loop_ret = 1;
345 goto loop_end;
346 }
347
348 loop_ret = lttng_register_trigger(trigger);
349
350 loop_end:
351 if (loop_ret == 1) {
352 fail("Setup error occurred for tuple: %s", test_tuple_string);
353 goto loop_cleanup;
354 }
355
356 /* This combination happens three times */
357 if (session_name_set && channel_name_set
358 && (threshold_ratio_set || threshold_byte_set)
359 && domain_type_set) {
360 ok(loop_ret == 0, "Trigger is registered: %s", test_tuple_string);
361
362 /*
363 * Test that a trigger cannot be registered
364 * multiple time.
365 */
366 loop_ret = lttng_register_trigger(trigger);
367 ok(loop_ret == -LTTNG_ERR_TRIGGER_EXISTS, "Re-register trigger fails as expected: %s", test_tuple_string);
368
369 /* Test that a trigger can be unregistered */
370 loop_ret = lttng_unregister_trigger(trigger);
371 ok(loop_ret == 0, "Unregister trigger: %s", test_tuple_string);
372
373 /*
374 * Test that unregistration of a non-previously
375 * registered trigger fail.
376 */
377 loop_ret = lttng_unregister_trigger(trigger);
378 ok(loop_ret == -LTTNG_ERR_TRIGGER_NOT_FOUND, "Unregister of a non-registered trigger fails as expected: %s", test_tuple_string);
379 } else {
380 ok(loop_ret == -LTTNG_ERR_INVALID_TRIGGER, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string);
381 }
382
383 loop_cleanup:
384 free(test_tuple_string);
385 lttng_trigger_destroy(trigger);
386 lttng_condition_destroy(condition);
387 }
388
389 end:
390 lttng_action_destroy(action);
391 }
392
393 static
394 void wait_data_pending(const char *session_name)
395 {
396 int ret;
397
398 do {
399 ret = lttng_data_pending(session_name);
400 assert(ret >= 0);
401 } while (ret != 0);
402 }
403
404 static
405 int setup_buffer_usage_condition(struct lttng_condition *condition,
406 const char *condition_name,
407 const char *session_name,
408 const char *channel_name,
409 const enum lttng_domain_type domain_type)
410 {
411 enum lttng_condition_status condition_status;
412 int ret = 0;
413
414 condition_status = lttng_condition_buffer_usage_set_session_name(
415 condition, session_name);
416 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
417 fail("Failed to set session name on creation of condition `%s`",
418 condition_name);
419 ret = -1;
420 goto end;
421 }
422
423 condition_status = lttng_condition_buffer_usage_set_channel_name(
424 condition, channel_name);
425 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
426 fail("Failed to set channel name on creation of condition `%s`",
427 condition_name);
428 ret = -1;
429 goto end;
430 }
431
432 condition_status = lttng_condition_buffer_usage_set_domain_type(
433 condition, domain_type);
434 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
435 fail("Failed to set domain type on creation of condition `%s`",
436 condition_name);
437 ret = -1;
438 goto end;
439 }
440
441 end:
442 return ret;
443 }
444
445 static
446 void test_invalid_channel_subscription(
447 const enum lttng_domain_type domain_type)
448 {
449 enum lttng_condition_status condition_status;
450 enum lttng_notification_channel_status nc_status;
451 struct lttng_condition *dummy_condition = NULL;
452 struct lttng_condition *dummy_invalid_condition = NULL;
453 struct lttng_notification_channel *notification_channel = NULL;
454 int ret = 0;
455
456 notification_channel = lttng_notification_channel_create(
457 lttng_session_daemon_notification_endpoint);
458 ok(notification_channel, "Notification channel object creation");
459 if (!notification_channel) {
460 goto end;
461 }
462
463 /*
464 * Create a dummy, empty (thus invalid) condition to test error paths.
465 */
466 dummy_invalid_condition = lttng_condition_buffer_usage_low_create();
467 if (!dummy_invalid_condition) {
468 fail("Setup error on condition creation");
469 goto end;
470 }
471
472 /*
473 * Test subscription and unsubscription of an invalid condition to/from
474 * a channel.
475 */
476 nc_status = lttng_notification_channel_subscribe(
477 notification_channel, dummy_invalid_condition);
478 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
479 "Subscribing to an invalid condition");
480
481 nc_status = lttng_notification_channel_unsubscribe(
482 notification_channel, dummy_invalid_condition);
483 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
484 "Unsubscribing from an invalid condition");
485
486 /* Create a valid dummy condition with a ratio of 0.5 */
487 dummy_condition = lttng_condition_buffer_usage_low_create();
488 if (!dummy_condition) {
489 fail("Setup error on dummy_condition creation");
490 goto end;
491 }
492
493 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
494 dummy_condition, 0.5);
495 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
496 fail("Setup error on condition creation");
497 goto end;
498 }
499
500 ret = setup_buffer_usage_condition(dummy_condition, "dummy_condition",
501 "dummy_session", "dummy_channel", domain_type);
502 if (ret) {
503 fail("Setup error on dummy condition creation");
504 goto end;
505 }
506
507 /*
508 * Test subscription and unsubscription to/from a channel with invalid
509 * parameters.
510 */
511 nc_status = lttng_notification_channel_subscribe(NULL, NULL);
512 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
513 "Notification channel subscription is invalid: NULL, NULL");
514
515 nc_status = lttng_notification_channel_subscribe(
516 notification_channel, NULL);
517 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
518 "Notification channel subscription is invalid: NON-NULL, NULL");
519
520 nc_status = lttng_notification_channel_subscribe(NULL, dummy_condition);
521 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
522 "Notification channel subscription is invalid: NULL, NON-NULL");
523
524 nc_status = lttng_notification_channel_unsubscribe(
525 notification_channel, dummy_condition);
526 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION,
527 "Unsubscribing from a valid unknown condition");
528
529 end:
530 lttng_notification_channel_destroy(notification_channel);
531 lttng_condition_destroy(dummy_invalid_condition);
532 lttng_condition_destroy(dummy_condition);
533 return;
534 }
535
536 enum buffer_usage_type {
537 BUFFER_USAGE_TYPE_LOW,
538 BUFFER_USAGE_TYPE_HIGH,
539 };
540
541 static int register_buffer_usage_notify_trigger(const char *session_name,
542 const char *channel_name,
543 const enum lttng_domain_type domain_type,
544 enum buffer_usage_type buffer_usage_type,
545 double ratio,
546 struct lttng_condition **condition,
547 struct lttng_action **action,
548 struct lttng_trigger **trigger)
549 {
550 enum lttng_condition_status condition_status;
551 struct lttng_action *tmp_action = NULL;
552 struct lttng_condition *tmp_condition = NULL;
553 struct lttng_trigger *tmp_trigger = NULL;
554 int ret = 0;
555
556 /* Set-up */
557 tmp_action = lttng_action_notify_create();
558 if (!action) {
559 fail("Setup error on action creation");
560 ret = -1;
561 goto error;
562 }
563
564 if (buffer_usage_type == BUFFER_USAGE_TYPE_LOW) {
565 tmp_condition = lttng_condition_buffer_usage_low_create();
566 } else {
567 tmp_condition = lttng_condition_buffer_usage_high_create();
568 }
569
570 if (!tmp_condition) {
571 fail("Setup error on condition creation");
572 ret = -1;
573 goto error;
574 }
575
576 /* Set the buffer usage threashold */
577 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
578 tmp_condition, ratio);
579 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
580 fail("Setup error on condition creation");
581 ret = -1;
582 goto error;
583 }
584
585 ret = setup_buffer_usage_condition(tmp_condition, "condition_name",
586 session_name, channel_name, domain_type);
587 if (ret) {
588 fail("Setup error on condition creation");
589 ret = -1;
590 goto error;
591 }
592
593 /* Register the trigger for condition. */
594 tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
595 if (!tmp_trigger) {
596 fail("Setup error on trigger creation");
597 ret = -1;
598 goto error;
599 }
600
601 ret = lttng_register_trigger(tmp_trigger);
602 if (ret) {
603 fail("Setup error on trigger registration");
604 ret = -1;
605 goto error;
606 }
607
608 *condition = tmp_condition;
609 *trigger = tmp_trigger;
610 *action = tmp_action;
611 goto end;
612
613 error:
614 lttng_action_destroy(tmp_action);
615 lttng_condition_destroy(tmp_condition);
616 lttng_trigger_destroy(tmp_trigger);
617
618 end:
619 return ret;
620 }
621
622 static void test_subscription_twice(const char *session_name,
623 const char *channel_name,
624 const enum lttng_domain_type domain_type)
625 {
626 int ret = 0;
627 enum lttng_notification_channel_status nc_status;
628
629 struct lttng_action *action = NULL;
630 struct lttng_notification_channel *notification_channel = NULL;
631 struct lttng_trigger *trigger = NULL;
632
633 struct lttng_condition *condition = NULL;
634
635 ret = register_buffer_usage_notify_trigger(session_name, channel_name,
636 domain_type, BUFFER_USAGE_TYPE_LOW, 0.99, &condition,
637 &action, &trigger);
638 if (ret) {
639 fail("Setup error on trigger registration");
640 goto end;
641 }
642
643 /* Begin testing. */
644 notification_channel = lttng_notification_channel_create(
645 lttng_session_daemon_notification_endpoint);
646 ok(notification_channel, "Notification channel object creation");
647 if (!notification_channel) {
648 goto end;
649 }
650
651 /* Subscribe a valid condition. */
652 nc_status = lttng_notification_channel_subscribe(
653 notification_channel, condition);
654 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
655 "Subscribe to condition");
656
657 /* Subscribing again should fail. */
658 nc_status = lttng_notification_channel_subscribe(
659 notification_channel, condition);
660 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED,
661 "Subscribe to a condition for which subscription was already done");
662
663 end:
664 lttng_unregister_trigger(trigger);
665 lttng_trigger_destroy(trigger);
666 lttng_notification_channel_destroy(notification_channel);
667 lttng_action_destroy(action);
668 lttng_condition_destroy(condition);
669 }
670
671 static void test_buffer_usage_notification_channel(const char *session_name,
672 const char *channel_name,
673 const enum lttng_domain_type domain_type,
674 const char **argv)
675 {
676 int ret = 0;
677 enum lttng_notification_channel_status nc_status;
678
679 struct lttng_action *low_action = NULL;
680 struct lttng_action *high_action = NULL;
681 struct lttng_notification *notification = NULL;
682 struct lttng_notification_channel *notification_channel = NULL;
683 struct lttng_trigger *low_trigger = NULL;
684 struct lttng_trigger *high_trigger = NULL;
685
686 struct lttng_condition *low_condition = NULL;
687 struct lttng_condition *high_condition = NULL;
688
689 const double low_ratio = 0.0;
690 const double high_ratio = 0.90;
691
692 ret = register_buffer_usage_notify_trigger(session_name, channel_name,
693 domain_type, BUFFER_USAGE_TYPE_LOW, low_ratio,
694 &low_condition, &low_action, &low_trigger);
695 if (ret) {
696 fail("Setup error on low trigger registration");
697 goto end;
698 }
699
700 ret = register_buffer_usage_notify_trigger(session_name, channel_name,
701 domain_type, BUFFER_USAGE_TYPE_HIGH, high_ratio,
702 &high_condition, &high_action, &high_trigger);
703 if (ret) {
704 fail("Setup error on high trigger registration");
705 goto end;
706 }
707
708 /* Begin testing */
709 notification_channel = lttng_notification_channel_create(
710 lttng_session_daemon_notification_endpoint);
711 ok(notification_channel, "Notification channel object creation");
712 if (!notification_channel) {
713 goto end;
714 }
715
716 /* Subscribe a valid low condition */
717 nc_status = lttng_notification_channel_subscribe(
718 notification_channel, low_condition);
719 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
720 "Subscribe to low condition");
721
722 /* Subscribe a valid high condition */
723 nc_status = lttng_notification_channel_subscribe(
724 notification_channel, high_condition);
725 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
726 "Subscribe to high condition");
727
728 resume_application();
729
730 /* Wait for notification to happen */
731 stop_consumer(argv);
732 lttng_start_tracing(session_name);
733
734 /* Wait for high notification */
735 do {
736 nc_status = lttng_notification_channel_get_next_notification(
737 notification_channel, &notification);
738 } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
739 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
740 lttng_condition_get_type(lttng_notification_get_condition(
741 notification)) ==
742 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
743 "High notification received after intermediary communication");
744 lttng_notification_destroy(notification);
745 notification = NULL;
746
747 suspend_application();
748 lttng_stop_tracing_no_wait(session_name);
749 resume_consumer(argv);
750 wait_data_pending(session_name);
751
752 /*
753 * Test that communication still work even if there is notification
754 * waiting for consumption.
755 */
756
757 nc_status = lttng_notification_channel_unsubscribe(
758 notification_channel, low_condition);
759 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
760 "Unsubscribe with pending notification");
761
762 nc_status = lttng_notification_channel_subscribe(
763 notification_channel, low_condition);
764 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
765 "Subscribe with pending notification");
766
767 do {
768 nc_status = lttng_notification_channel_get_next_notification(
769 notification_channel, &notification);
770 } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
771 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
772 lttng_condition_get_type(lttng_notification_get_condition(
773 notification)) ==
774 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
775 "Low notification received after intermediary communication");
776 lttng_notification_destroy(notification);
777 notification = NULL;
778
779 /* Stop consumer to force a high notification */
780 stop_consumer(argv);
781 resume_application();
782 lttng_start_tracing(session_name);
783
784 do {
785 nc_status = lttng_notification_channel_get_next_notification(
786 notification_channel, &notification);
787 } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
788 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
789 lttng_condition_get_type(lttng_notification_get_condition(
790 notification)) ==
791 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
792 "High notification received after intermediary communication");
793 lttng_notification_destroy(notification);
794 notification = NULL;
795
796 suspend_application();
797 lttng_stop_tracing_no_wait(session_name);
798 resume_consumer(argv);
799 wait_data_pending(session_name);
800
801 do {
802 nc_status = lttng_notification_channel_get_next_notification(
803 notification_channel, &notification);
804 } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
805 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
806 lttng_condition_get_type(lttng_notification_get_condition(
807 notification)) ==
808 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
809 "Low notification received after re-subscription");
810 lttng_notification_destroy(notification);
811 notification = NULL;
812
813 stop_consumer(argv);
814 resume_application();
815 /* Stop consumer to force a high notification */
816 lttng_start_tracing(session_name);
817
818 do {
819 nc_status = lttng_notification_channel_get_next_notification(
820 notification_channel, &notification);
821 } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
822 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
823 lttng_condition_get_type(lttng_notification_get_condition(
824 notification)) ==
825 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
826 "High notification");
827 lttng_notification_destroy(notification);
828 notification = NULL;
829
830 suspend_application();
831
832 /* Resume consumer to allow event consumption */
833 lttng_stop_tracing_no_wait(session_name);
834 resume_consumer(argv);
835 wait_data_pending(session_name);
836
837 nc_status = lttng_notification_channel_unsubscribe(
838 notification_channel, low_condition);
839 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
840 "Unsubscribe low condition with pending notification");
841
842 nc_status = lttng_notification_channel_unsubscribe(
843 notification_channel, high_condition);
844 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
845 "Unsubscribe high condition with pending notification");
846
847 end:
848 lttng_notification_channel_destroy(notification_channel);
849 lttng_trigger_destroy(low_trigger);
850 lttng_trigger_destroy(high_trigger);
851 lttng_action_destroy(low_action);
852 lttng_action_destroy(high_action);
853 lttng_condition_destroy(low_condition);
854 lttng_condition_destroy(high_condition);
855 }
856
857 static void create_tracepoint_event_rule_trigger(const char *event_pattern,
858 const char *trigger_name,
859 const char *filter,
860 unsigned int exclusion_count,
861 const char * const *exclusions,
862 enum lttng_domain_type domain_type,
863 struct lttng_condition **condition,
864 struct lttng_trigger **trigger)
865 {
866 enum lttng_event_rule_status event_rule_status;
867 enum lttng_trigger_status trigger_status;
868
869 struct lttng_action *tmp_action = NULL;
870 struct lttng_event_rule *event_rule = NULL;
871 struct lttng_condition *tmp_condition = NULL;
872 struct lttng_trigger *tmp_trigger = NULL;
873 int ret;
874
875 assert(event_pattern);
876 assert(trigger_name);
877 assert(condition);
878 assert(trigger);
879
880 event_rule = lttng_event_rule_tracepoint_create(domain_type);
881 ok(event_rule, "Tracepoint event rule object creation");
882
883 event_rule_status = lttng_event_rule_tracepoint_set_pattern(
884 event_rule, event_pattern);
885 ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
886 "Setting tracepoint event rule pattern: '%s'",
887 event_pattern);
888
889 if (filter) {
890 event_rule_status = lttng_event_rule_tracepoint_set_filter(
891 event_rule, filter);
892 ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
893 "Setting tracepoint event rule filter: '%s'",
894 filter);
895 }
896
897 if (exclusions) {
898 int i;
899 bool success = true;
900
901 assert(domain_type == LTTNG_DOMAIN_UST);
902 assert(exclusion_count > 0);
903
904 for (i = 0; i < exclusion_count; i++) {
905 event_rule_status =
906 lttng_event_rule_tracepoint_add_exclusion(
907 event_rule,
908 exclusions[i]);
909 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
910 fail("Setting tracepoint event rule exclusion '%s'.",
911 exclusions[i]);
912 success = false;
913 }
914 }
915
916 ok(success, "Setting tracepoint event rule exclusions");
917 }
918
919 tmp_condition = lttng_condition_event_rule_create(event_rule);
920 ok(tmp_condition, "Condition event rule object creation");
921
922 tmp_action = lttng_action_notify_create();
923 ok(tmp_action, "Action event rule object creation");
924
925 tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
926 ok(tmp_trigger, "Trigger object creation %s", trigger_name);
927
928 trigger_status = lttng_trigger_set_name(tmp_trigger, trigger_name);
929 ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
930 "Setting name to trigger %s", trigger_name);
931
932 ret = lttng_register_trigger(tmp_trigger);
933 ok(ret == 0, "Trigger registration %s", trigger_name);
934
935 lttng_event_rule_destroy(event_rule);
936
937 *condition = tmp_condition;
938 *trigger = tmp_trigger;
939
940 return;
941 }
942
943 static char *get_next_notification_trigger_name(
944 struct lttng_notification_channel *notification_channel)
945 {
946 struct lttng_notification *notification;
947 enum lttng_notification_channel_status status;
948 const struct lttng_evaluation *notification_evaluation;
949 char *trigger_name = NULL;
950 const char *name;
951 enum lttng_condition_type notification_evaluation_type;
952
953 /* Receive the next notification. */
954 status = lttng_notification_channel_get_next_notification(
955 notification_channel, &notification);
956
957 switch (status) {
958 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
959 break;
960 default:
961 /* Unhandled conditions / errors. */
962 fail("Failed to get next notification channel notification: status = %d",
963 status);
964 goto end;
965 }
966
967 notification_evaluation =
968 lttng_notification_get_evaluation(notification);
969
970 notification_evaluation_type =
971 lttng_evaluation_get_type(notification_evaluation);
972 switch (notification_evaluation_type) {
973 case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
974 lttng_evaluation_event_rule_get_trigger_name(
975 notification_evaluation, &name);
976
977 trigger_name = strdup(name);
978 break;
979 default:
980 fail("Unexpected notification evaluation type: notification type = %d",
981 notification_evaluation_type);
982 break;
983 }
984
985 lttng_notification_destroy(notification);
986
987 end:
988 return trigger_name;
989 }
990
991 static void test_tracepoint_event_rule_notification(
992 enum lttng_domain_type domain_type)
993 {
994 int i;
995 const int notification_count = 3;
996 enum lttng_notification_channel_status nc_status;
997 struct lttng_action *action = NULL;
998 struct lttng_condition *condition = NULL;
999 struct lttng_notification_channel *notification_channel = NULL;
1000 struct lttng_trigger *trigger = NULL;
1001 const char * const trigger_name = "my_precious";
1002 const char *pattern;
1003
1004 if (domain_type == LTTNG_DOMAIN_UST) {
1005 pattern = "tp:tptest";
1006 } else {
1007 pattern = "lttng_test_filter_event";
1008 }
1009
1010 create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
1011 NULL, domain_type, &condition, &trigger);
1012
1013 notification_channel = lttng_notification_channel_create(
1014 lttng_session_daemon_notification_endpoint);
1015 ok(notification_channel, "Notification channel object creation");
1016
1017 nc_status = lttng_notification_channel_subscribe(
1018 notification_channel, condition);
1019 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
1020 "Subscribe to tracepoint event rule condition");
1021
1022 resume_application();
1023
1024 /* Get 3 notifications. */
1025 for (i = 0; i < notification_count; i++) {
1026 char *name = get_next_notification_trigger_name(
1027 notification_channel);
1028
1029 ok(strcmp(trigger_name, name) == 0,
1030 "Received notification for the expected trigger name: '%s' (%d/%d)",
1031 trigger_name, i + 1, notification_count);
1032 free(name);
1033 }
1034
1035 suspend_application();
1036 lttng_notification_channel_destroy(notification_channel);
1037 lttng_unregister_trigger(trigger);
1038 lttng_trigger_destroy(trigger);
1039 lttng_action_destroy(action);
1040 lttng_condition_destroy(condition);
1041 return;
1042 }
1043
1044 static void test_tracepoint_event_rule_notification_filter(
1045 enum lttng_domain_type domain_type)
1046 {
1047 int i;
1048 enum lttng_notification_channel_status nc_status;
1049
1050 struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
1051 struct lttng_notification_channel *notification_channel = NULL;
1052 struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
1053 const char * const ctrl_trigger_name = "control_trigger";
1054 const char * const trigger_name = "trigger";
1055 const char *pattern;
1056 int ctrl_count = 0, count = 0;
1057
1058 if (domain_type == LTTNG_DOMAIN_UST) {
1059 pattern = "tp:tptest";
1060 } else {
1061 pattern = "lttng_test_filter_event";
1062 }
1063
1064 notification_channel = lttng_notification_channel_create(
1065 lttng_session_daemon_notification_endpoint);
1066 ok(notification_channel, "Notification channel object creation");
1067
1068 create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
1069 0, NULL, domain_type, &ctrl_condition, &ctrl_trigger);
1070
1071 nc_status = lttng_notification_channel_subscribe(
1072 notification_channel, ctrl_condition);
1073 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
1074 "Subscribe to tracepoint event rule condition");
1075
1076 /*
1077 * Attach a filter expression to get notification only if the
1078 * `intfield` is even.
1079 */
1080 create_tracepoint_event_rule_trigger(pattern, trigger_name,
1081 "(intfield & 1) == 0", 0, NULL, domain_type, &condition,
1082 &trigger);
1083
1084 nc_status = lttng_notification_channel_subscribe(
1085 notification_channel, condition);
1086 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
1087 "Subscribe to tracepoint event rule condition");
1088
1089 /*
1090 * We registered 2 notifications triggers, one with a filter and one
1091 * without (control). The one with a filter will only fired when the
1092 * `intfield` is a multiple of 2. We should get two times as many
1093 * control notifications as filter notifications.
1094 */
1095 resume_application();
1096
1097 /*
1098 * Get 3 notifications. We should get 1 for the regular trigger (with
1099 * the filter) and 2 from the control trigger. This works whatever
1100 * the order we receive the notifications.
1101 */
1102 for (i = 0; i < 3; i++) {
1103 char *name = get_next_notification_trigger_name(
1104 notification_channel);
1105
1106 if (strcmp(ctrl_trigger_name, name) == 0) {
1107 ctrl_count++;
1108 } else if (strcmp(trigger_name, name) == 0) {
1109 count++;
1110 }
1111
1112 free(name);
1113 }
1114
1115 ok(ctrl_count / 2 == count,
1116 "Get twice as many control notif as of regular notif");
1117
1118 suspend_application();
1119
1120 lttng_unregister_trigger(trigger);
1121 lttng_unregister_trigger(ctrl_trigger);
1122 lttng_notification_channel_destroy(notification_channel);
1123 lttng_trigger_destroy(trigger);
1124 lttng_trigger_destroy(ctrl_trigger);
1125 lttng_condition_destroy(condition);
1126 lttng_condition_destroy(ctrl_condition);
1127 }
1128
1129 static void test_tracepoint_event_rule_notification_exclusion(
1130 enum lttng_domain_type domain_type)
1131 {
1132 enum lttng_notification_channel_status nc_status;
1133 struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
1134 struct lttng_notification_channel *notification_channel = NULL;
1135 struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
1136 int ctrl_count = 0, count = 0, i;
1137 const char * const ctrl_trigger_name = "control_exclusion_trigger";
1138 const char * const trigger_name = "exclusion_trigger";
1139 const char * const pattern = "tp:tptest*";
1140 const char * const exclusions[] = {
1141 "tp:tptest2",
1142 "tp:tptest3",
1143 "tp:tptest4",
1144 "tp:tptest5"
1145 };
1146
1147 notification_channel = lttng_notification_channel_create(
1148 lttng_session_daemon_notification_endpoint);
1149 ok(notification_channel, "Notification channel object creation");
1150
1151 create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
1152 0, NULL, domain_type, &ctrl_condition, &ctrl_trigger);
1153
1154 nc_status = lttng_notification_channel_subscribe(
1155 notification_channel, ctrl_condition);
1156 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
1157 "Subscribe to tracepoint event rule condition");
1158
1159 create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 4,
1160 exclusions, domain_type, &condition, &trigger);
1161
1162 nc_status = lttng_notification_channel_subscribe(
1163 notification_channel, condition);
1164 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
1165 "Subscribe to tracepoint event rule condition");
1166
1167 /*
1168 * We registered 2 notifications triggers, one with an exclusion and
1169 * one without (control).
1170 * - The trigger with an exclusion will fire once every iteration.
1171 * - The trigger without an exclusion will fire 5 times every
1172 * iteration.
1173 *
1174 * We should get 5 times as many notifications from the control
1175 * trigger.
1176 */
1177 resume_application();
1178
1179 /*
1180 * Get 6 notifications. We should get 1 for the regular trigger (with
1181 * the exclusion) and 5 from the control trigger. This works whatever
1182 * the order we receive the notifications.
1183 */
1184 for (i = 0; i < 6; i++) {
1185 char *name = get_next_notification_trigger_name(
1186 notification_channel);
1187
1188 if (strcmp(ctrl_trigger_name, name) == 0) {
1189 ctrl_count++;
1190 } else if (strcmp(trigger_name, name) == 0) {
1191 count++;
1192 }
1193
1194 free(name);
1195 }
1196
1197 ok(ctrl_count / 5 == count,
1198 "Got 5 times as many control notif as of regular notif");
1199
1200 suspend_application();
1201
1202 lttng_unregister_trigger(trigger);
1203 lttng_unregister_trigger(ctrl_trigger);
1204 lttng_notification_channel_destroy(notification_channel);
1205 lttng_trigger_destroy(trigger);
1206 lttng_trigger_destroy(ctrl_trigger);
1207 lttng_condition_destroy(condition);
1208 lttng_condition_destroy(ctrl_condition);
1209 return;
1210 }
1211
1212 static void test_kprobe_event_rule_notification(
1213 enum lttng_domain_type domain_type)
1214 {
1215 int i, ret;
1216 const int notification_count = 3;
1217 enum lttng_notification_channel_status nc_status;
1218 enum lttng_event_rule_status event_rule_status;
1219 enum lttng_trigger_status trigger_status;
1220 struct lttng_notification_channel *notification_channel = NULL;
1221 struct lttng_condition *condition = NULL;
1222 struct lttng_kernel_probe_location *location = NULL;
1223 struct lttng_event_rule *event_rule = NULL;
1224 struct lttng_action *action = NULL;
1225 struct lttng_trigger *trigger = NULL;
1226 const char * const trigger_name = "kprobe_trigger";
1227 const char * const symbol_name = "lttng_test_filter_event_write";
1228
1229 action = lttng_action_notify_create();
1230 if (!action) {
1231 fail("Failed to create notify action");
1232 goto end;
1233 }
1234
1235 location = lttng_kernel_probe_location_symbol_create(symbol_name, 0);
1236 if (!location) {
1237 fail("Failed to create kernel probe location");
1238 goto end;
1239 }
1240
1241 notification_channel = lttng_notification_channel_create(
1242 lttng_session_daemon_notification_endpoint);
1243 ok(notification_channel, "Notification channel object creation");
1244
1245 event_rule = lttng_event_rule_kprobe_create();
1246 ok(event_rule, "kprobe event rule object creation");
1247
1248 event_rule_status = lttng_event_rule_kprobe_set_location(
1249 event_rule, location);
1250 ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
1251 "Setting kprobe event rule location: '%s'", symbol_name);
1252
1253 event_rule_status = lttng_event_rule_kprobe_set_name(
1254 event_rule, trigger_name);
1255 ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
1256 "Setting kprobe event rule name: '%s'", trigger_name);
1257
1258 condition = lttng_condition_event_rule_create(event_rule);
1259 ok(condition, "Condition event rule object creation");
1260
1261 /* Register the trigger for condition. */
1262 trigger = lttng_trigger_create(condition, action);
1263 if (!trigger) {
1264 fail("Failed to create trigger with kernel probe event rule condition and notify action");
1265 goto end;
1266 }
1267
1268 trigger_status = lttng_trigger_set_name(trigger, trigger_name);
1269 ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
1270 "Setting trigger name to '%s'", trigger_name);
1271
1272 ret = lttng_register_trigger(trigger);
1273 if (ret) {
1274 fail("Failed to register trigger with kernel probe event rule condition and notify action");
1275 goto end;
1276 }
1277
1278 nc_status = lttng_notification_channel_subscribe(
1279 notification_channel, condition);
1280 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
1281 "Subscribe to tracepoint event rule condition");
1282
1283 resume_application();
1284
1285 for (i = 0; i < notification_count; i++) {
1286 char *name = get_next_notification_trigger_name(
1287 notification_channel);
1288
1289 ok(strcmp(trigger_name, name) == 0,
1290 "Received notification for the expected trigger name: '%s' (%d/%d)",
1291 trigger_name, i + 1, notification_count);
1292 free(name);
1293 }
1294
1295 end:
1296 suspend_application();
1297 lttng_notification_channel_destroy(notification_channel);
1298 lttng_unregister_trigger(trigger);
1299 lttng_trigger_destroy(trigger);
1300 lttng_action_destroy(action);
1301 lttng_condition_destroy(condition);
1302 lttng_kernel_probe_location_destroy(location);
1303 return;
1304 }
1305
1306 int main(int argc, const char *argv[])
1307 {
1308 int test_scenario;
1309 const char *session_name = NULL;
1310 const char *channel_name = NULL;
1311 const char *domain_type_string = NULL;
1312 enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
1313
1314 if (argc < 5) {
1315 fail("Missing test scenario, domain type, pid, or application state file argument(s)");
1316 goto error;
1317 }
1318
1319 test_scenario = atoi(argv[1]);
1320 domain_type_string = argv[2];
1321 app_pid = (pid_t) atoi(argv[3]);
1322 app_state_file = argv[4];
1323
1324 if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string)) {
1325 domain_type = LTTNG_DOMAIN_UST;
1326 }
1327 if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
1328 domain_type = LTTNG_DOMAIN_KERNEL;
1329 }
1330 if (domain_type == LTTNG_DOMAIN_NONE) {
1331 fail("Unknown domain type");
1332 goto error;
1333 }
1334
1335 /*
1336 * Test cases are responsible for resuming the app when needed
1337 * and making sure it's suspended when returning.
1338 */
1339 suspend_application();
1340
1341 switch (test_scenario) {
1342 case 1:
1343 {
1344 plan_tests(38);
1345
1346 /* Test cases that need gen-ust-event testapp. */
1347 diag("Test basic notification error paths for %s domain",
1348 domain_type_string);
1349 test_invalid_channel_subscription(domain_type);
1350
1351 diag("Test tracepoint event rule notifications for domain %s",
1352 domain_type_string);
1353 test_tracepoint_event_rule_notification(domain_type);
1354
1355 diag("Test tracepoint event rule notifications with filter for domain %s",
1356 domain_type_string);
1357 test_tracepoint_event_rule_notification_filter(domain_type);
1358 break;
1359 }
1360 case 2:
1361 {
1362 /* Test cases that need a tracing session enabled. */
1363 plan_tests(99);
1364
1365 /*
1366 * Argument 7 and upward are named pipe location for consumerd
1367 * control.
1368 */
1369 named_pipe_args_start = 7;
1370
1371 if (argc < 8) {
1372 fail("Missing parameter for tests to run %d", argc);
1373 goto error;
1374 }
1375
1376 nb_args = argc;
1377
1378 session_name = argv[5];
1379 channel_name = argv[6];
1380
1381 test_subscription_twice(session_name, channel_name,
1382 domain_type);
1383
1384 diag("Test trigger for domain %s with buffer_usage_low condition",
1385 domain_type_string);
1386 test_triggers_buffer_usage_condition(session_name, channel_name,
1387 domain_type,
1388 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
1389
1390 diag("Test trigger for domain %s with buffer_usage_high condition",
1391 domain_type_string);
1392 test_triggers_buffer_usage_condition(session_name, channel_name,
1393 domain_type,
1394 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
1395
1396 diag("Test buffer usage notification channel api for domain %s",
1397 domain_type_string);
1398 test_buffer_usage_notification_channel(session_name, channel_name,
1399 domain_type, argv);
1400 break;
1401 }
1402 case 3:
1403 {
1404 /*
1405 * Test cases that need a test app with more than one event
1406 * type.
1407 */
1408 plan_tests(19);
1409
1410 /*
1411 * At the moment, the only test case of this scenario is
1412 * exclusion which is only supported by UST.
1413 */
1414 assert(domain_type == LTTNG_DOMAIN_UST);
1415 diag("Test tracepoint event rule notifications with exclusion for domain %s",
1416 domain_type_string);
1417 test_tracepoint_event_rule_notification_exclusion(domain_type);
1418
1419 break;
1420 }
1421 case 4:
1422 {
1423 plan_tests(10);
1424
1425 /* Test cases that need the kernel tracer. */
1426 assert(domain_type == LTTNG_DOMAIN_KERNEL);
1427 diag("Test kprobe event rule notifications for domain %s",
1428 domain_type_string);
1429
1430 test_kprobe_event_rule_notification(domain_type);
1431
1432 break;
1433 }
1434 default:
1435 abort();
1436 }
1437
1438 error:
1439 return exit_status();
1440 }
1441
This page took 0.060355 seconds and 4 git commands to generate.