4 * Tests suite for LTTng notification API
6 * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
8 * SPDX-License-Identifier: MIT
20 #include <sys/types.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/domain.h>
33 #include <lttng/endpoint.h>
34 #include <lttng/lttng-error.h>
35 #include <lttng/notification/channel.h>
36 #include <lttng/notification/notification.h>
37 #include <lttng/trigger/trigger.h>
38 #include <lttng/lttng.h>
45 int named_pipe_args_start
= 0;
47 const char *app_state_file
= NULL
;
50 void wait_on_file(const char *path
, bool file_exist
)
59 ret
= stat(path
, &buf
);
60 if (ret
== -1 && errno
== ENOENT
) {
62 (void) poll(NULL
, 0, 10); /* 10 ms delay */
65 break; /* File does not exist */
75 int write_pipe(const char *path
, uint8_t data
)
80 fd
= open(path
, O_WRONLY
| O_NONBLOCK
);
82 perror("Could not open consumer control named pipe");
86 ret
= write(fd
, &data
, sizeof(data
));
88 perror("Named pipe write failed");
90 perror("Named pipe close failed");
98 perror("Name pipe closing failed");
106 int stop_consumer(const char **argv
)
109 for (int i
= named_pipe_args_start
; i
< nb_args
; i
++) {
110 ret
= write_pipe(argv
[i
], 49);
115 int resume_consumer(const char **argv
)
118 for (int i
= named_pipe_args_start
; i
< nb_args
; i
++) {
119 ret
= write_pipe(argv
[i
], 0);
124 int suspend_application()
129 if (!stat(app_state_file
, &buf
)) {
130 fail("App is already in a suspended state.");
136 * Send SIGUSR1 to application instructing it to bypass tracepoint.
138 ret
= kill(app_pid
, SIGUSR1
);
140 fail("SIGUSR1 failed. errno %d", errno
);
145 wait_on_file(app_state_file
, true);
152 int resume_application()
157 ret
= stat(app_state_file
, &buf
);
158 if (ret
== -1 && errno
== ENOENT
) {
159 fail("State file does not exist");
167 ret
= kill(app_pid
, SIGUSR1
);
169 fail("SIGUSR1 failed. errno %d", errno
);
174 wait_on_file(app_state_file
, false);
182 void test_triggers_buffer_usage_condition(const char *session_name
,
183 const char *channel_name
,
184 enum lttng_domain_type domain_type
,
185 enum lttng_condition_type condition_type
)
187 enum lttng_condition_status condition_status
;
188 struct lttng_action
*action
;
191 action
= lttng_action_notify_create();
193 fail("Setup error on action creation");
197 /* Test lttng_register_trigger with null value */
198 ok(lttng_register_trigger(NULL
) == -LTTNG_ERR_INVALID
, "Registering a NULL trigger fails as expected");
200 /* Test: register a trigger */
201 unsigned int test_vector_size
= 5;
202 for (unsigned int i
= 0; i
< pow(2,test_vector_size
); i
++) {
204 char *test_tuple_string
= NULL
;
205 unsigned int mask_position
= 0;
206 bool session_name_set
= false;
207 bool channel_name_set
= false;
208 bool threshold_ratio_set
= false;
209 bool threshold_byte_set
= false;
210 bool domain_type_set
= false;
212 struct lttng_trigger
*trigger
= NULL
;
213 struct lttng_condition
*condition
= NULL
;
215 /* Create base condition */
216 switch (condition_type
) {
217 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
:
218 condition
= lttng_condition_buffer_usage_low_create();
220 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
:
221 condition
= lttng_condition_buffer_usage_high_create();
234 /* Prepare the condition for trigger registration test */
236 /* Set session name */
237 if ((1 << mask_position
) & i
) {
238 condition_status
= lttng_condition_buffer_usage_set_session_name(
239 condition
, session_name
);
240 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
244 session_name_set
= true;
248 /* Set channel name */
249 if ((1 << mask_position
) & i
) {
250 condition_status
= lttng_condition_buffer_usage_set_channel_name(
251 condition
, channel_name
);
252 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
256 channel_name_set
= true;
260 /* Set threshold ratio */
261 if ((1 << mask_position
) & i
) {
262 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
264 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
268 threshold_ratio_set
= true;
272 /* Set threshold byte */
273 if ((1 << mask_position
) & i
) {
274 condition_status
= lttng_condition_buffer_usage_set_threshold(
276 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
280 threshold_byte_set
= true;
284 /* Set domain type */
285 if ((1 << mask_position
) & i
) {
286 condition_status
= lttng_condition_buffer_usage_set_domain_type(
287 condition
, LTTNG_DOMAIN_UST
);
288 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
292 domain_type_set
= true;
296 if (mask_position
!= test_vector_size
-1) {
297 assert("Logic error for test vector generation");
300 loop_ret
= asprintf(&test_tuple_string
, "session name %s, channel name %s, threshold ratio %s, threshold byte %s, domain type %s",
301 session_name_set
? "set" : "unset",
302 channel_name_set
? "set" : "unset",
303 threshold_ratio_set
? "set" : "unset",
304 threshold_byte_set
? "set" : "unset",
305 domain_type_set
? "set" : "unset");
306 if (!test_tuple_string
|| loop_ret
< 0) {
312 trigger
= lttng_trigger_create(condition
, action
);
318 loop_ret
= lttng_register_trigger(trigger
);
322 fail("Setup error occurred for tuple: %s", test_tuple_string
);
326 /* This combination happens three times */
327 if (session_name_set
&& channel_name_set
328 && (threshold_ratio_set
|| threshold_byte_set
)
329 && domain_type_set
) {
330 ok(loop_ret
== 0, "Trigger is registered: %s", test_tuple_string
);
333 * Test that a trigger cannot be registered
336 loop_ret
= lttng_register_trigger(trigger
);
337 ok(loop_ret
== -LTTNG_ERR_TRIGGER_EXISTS
, "Re-register trigger fails as expected: %s", test_tuple_string
);
339 /* Test that a trigger can be unregistered */
340 loop_ret
= lttng_unregister_trigger(trigger
);
341 ok(loop_ret
== 0, "Unregister trigger: %s", test_tuple_string
);
344 * Test that unregistration of a non-previously
345 * registered trigger fail.
347 loop_ret
= lttng_unregister_trigger(trigger
);
348 ok(loop_ret
== -LTTNG_ERR_TRIGGER_NOT_FOUND
, "Unregister of a non-registerd trigger fails as expected: %s", test_tuple_string
);
350 ok(loop_ret
== -LTTNG_ERR_INVALID_TRIGGER
, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string
);
354 free(test_tuple_string
);
355 lttng_trigger_destroy(trigger
);
356 lttng_condition_destroy(condition
);
360 lttng_action_destroy(action
);
364 void wait_data_pending(const char *session_name
)
369 ret
= lttng_data_pending(session_name
);
374 void test_notification_channel(const char *session_name
, const char *channel_name
, const enum lttng_domain_type domain_type
, const char **argv
)
377 enum lttng_condition_status condition_status
;
378 enum lttng_notification_channel_status nc_status
;
380 struct lttng_action
*action
= NULL
;
381 struct lttng_notification
*notification
= NULL
;
382 struct lttng_notification_channel
*notification_channel
= NULL
;
383 struct lttng_trigger
*trigger
= NULL
;
385 struct lttng_condition
*low_condition
= NULL
;
386 struct lttng_condition
*high_condition
= NULL
;
387 struct lttng_condition
*dummy_invalid_condition
= NULL
;
388 struct lttng_condition
*dummy_condition
= NULL
;
390 double low_ratio
= 0.0;
391 double high_ratio
= 0.99;
394 action
= lttng_action_notify_create();
396 fail("Setup error on action creation");
400 /* Create a dummy, empty condition for later test */
401 dummy_invalid_condition
= lttng_condition_buffer_usage_low_create();
402 if (!dummy_invalid_condition
) {
403 fail("Setup error on condition creation");
407 /* Create a valid dummy condition with a ratio of 0.5 */
408 dummy_condition
= lttng_condition_buffer_usage_low_create();
409 if (!dummy_condition
) {
410 fail("Setup error on dummy_condition creation");
414 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
415 dummy_condition
, 0.5);
416 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
417 fail("Setup error on condition creation");
421 condition_status
= lttng_condition_buffer_usage_set_session_name(
422 dummy_condition
, session_name
);
423 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
424 fail("Setup error on dummy_condition creation");
427 condition_status
= lttng_condition_buffer_usage_set_channel_name(
428 dummy_condition
, channel_name
);
429 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
430 fail("Setup error on dummy_condition creation");
433 condition_status
= lttng_condition_buffer_usage_set_domain_type(
434 dummy_condition
, domain_type
);
435 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
436 fail("Setup error on dummy_condition creation");
440 /* Register a low condition with a ratio */
441 low_condition
= lttng_condition_buffer_usage_low_create();
442 if (!low_condition
) {
443 fail("Setup error on low_condition creation");
446 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
447 low_condition
, low_ratio
);
448 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
449 fail("Setup error on low_condition creation");
453 condition_status
= lttng_condition_buffer_usage_set_session_name(
454 low_condition
, session_name
);
455 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
456 fail("Setup error on low_condition creation");
459 condition_status
= lttng_condition_buffer_usage_set_channel_name(
460 low_condition
, channel_name
);
461 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
462 fail("Setup error on low_condition creation");
465 condition_status
= lttng_condition_buffer_usage_set_domain_type(
466 low_condition
, domain_type
);
467 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
468 fail("Setup error on low_condition creation");
473 /* Register a high condition with a ratio */
474 high_condition
= lttng_condition_buffer_usage_high_create();
475 if (!high_condition
) {
476 fail("Setup error on high_condition creation");
480 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
481 high_condition
, high_ratio
);
482 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
483 fail("Setup error on high_condition creation");
487 condition_status
= lttng_condition_buffer_usage_set_session_name(
488 high_condition
, session_name
);
489 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
490 fail("Setup error on high_condition creation");
493 condition_status
= lttng_condition_buffer_usage_set_channel_name(
494 high_condition
, channel_name
);
495 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
496 fail("Setup error on high_condition creation");
499 condition_status
= lttng_condition_buffer_usage_set_domain_type(
500 high_condition
, domain_type
);
501 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
502 fail("Setup error on high_condition creation");
506 /* Register the triggers for low and high condition */
507 trigger
= lttng_trigger_create(low_condition
, action
);
509 fail("Setup error on low trigger creation");
513 ret
= lttng_register_trigger(trigger
);
515 fail("Setup error on low trigger registration");
519 lttng_trigger_destroy(trigger
);
522 trigger
= lttng_trigger_create(high_condition
, action
);
524 fail("Setup error on high trigger creation");
528 ret
= lttng_register_trigger(trigger
);
530 fail("Setup error on high trigger registration");
535 notification_channel
= lttng_notification_channel_create(lttng_session_daemon_notification_endpoint
);
536 ok(notification_channel
, "Notification channel object creation");
537 if (!notification_channel
) {
541 /* Basic error path check */
542 nc_status
= lttng_notification_channel_subscribe(NULL
, NULL
);
543 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Notification channel subscription is invalid: NULL, NULL");
545 nc_status
= lttng_notification_channel_subscribe(notification_channel
, NULL
);
546 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Notification channel subscription is invalid: NON-NULL, NULL");
548 nc_status
= lttng_notification_channel_subscribe(NULL
, low_condition
);
549 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Notification channel subscription is invalid: NULL, NON-NULL");
551 nc_status
= lttng_notification_channel_subscribe(notification_channel
, dummy_invalid_condition
);
552 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Subscribing to an invalid condition");
554 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, dummy_invalid_condition
);
555 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Unsubscribing from an invalid condition");
557 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, dummy_condition
);
558 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION
, "Unsubscribing from a valid unknown condition");
560 /* Subscribe a valid low condition */
561 nc_status
= lttng_notification_channel_subscribe(notification_channel
, low_condition
);
562 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Subscribe to condition");
564 /* Subscribe a valid high condition */
565 nc_status
= lttng_notification_channel_subscribe(notification_channel
, high_condition
);
566 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Subscribe to condition");
568 nc_status
= lttng_notification_channel_subscribe(notification_channel
, low_condition
);
569 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED
, "Subscribe to a condition for which subscription was already done");
571 nc_status
= lttng_notification_channel_subscribe(notification_channel
, high_condition
);
572 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED
, "Subscribe to a condition for which subscription was already done");
574 /* Wait for notification to happen */
576 lttng_start_tracing(session_name
);
578 /* Wait for high notification */
579 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
580 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
582 && lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
,
583 "High notification received after intermediary communication");
584 lttng_notification_destroy(notification
);
587 suspend_application();
588 lttng_stop_tracing_no_wait(session_name
);
589 resume_consumer(argv
);
590 wait_data_pending(session_name
);
593 * Test that communication still work even if there is notification
594 * waiting for consumption.
597 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, low_condition
);
598 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Unsubscribe with pending notification");
600 nc_status
= lttng_notification_channel_subscribe(notification_channel
, low_condition
);
601 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "subscribe with pending notification");
603 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
604 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
606 && lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
,
607 "Low notification received after intermediary communication");
608 lttng_notification_destroy(notification
);
611 /* Stop consumer to force a high notification */
613 resume_application();
614 lttng_start_tracing(session_name
);
616 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
617 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
&& notification
&&
618 lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
,
619 "High notification received after intermediary communication");
620 lttng_notification_destroy(notification
);
623 suspend_application();
624 lttng_stop_tracing_no_wait(session_name
);
625 resume_consumer(argv
);
626 wait_data_pending(session_name
);
628 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
629 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
&& notification
&&
630 lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
,
631 "Low notification received after re-subscription");
632 lttng_notification_destroy(notification
);
636 resume_application();
637 /* Stop consumer to force a high notification */
638 lttng_start_tracing(session_name
);
640 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
641 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
&& notification
&&
642 lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
,
643 "High notification");
644 lttng_notification_destroy(notification
);
647 /* Resume consumer to allow event consumption */
648 suspend_application();
649 lttng_stop_tracing_no_wait(session_name
);
650 resume_consumer(argv
);
651 wait_data_pending(session_name
);
653 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, low_condition
);
654 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Unsubscribe low condition with pending notification");
655 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, high_condition
);
656 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Unsubscribe high condition with pending notification");
659 lttng_notification_channel_destroy(notification_channel
);
660 lttng_trigger_destroy(trigger
);
661 lttng_action_destroy(action
);
662 lttng_condition_destroy(low_condition
);
663 lttng_condition_destroy(high_condition
);
664 lttng_condition_destroy(dummy_invalid_condition
);
665 lttng_condition_destroy(dummy_condition
);
668 int main(int argc
, const char *argv
[])
670 const char *session_name
= NULL
;
671 const char *channel_name
= NULL
;
672 const char *domain_type_string
= NULL
;
673 enum lttng_domain_type domain_type
= LTTNG_DOMAIN_NONE
;
675 plan_tests(NUM_TESTS
);
677 /* Argument 6 and upward are named pipe location for consumerd control */
678 named_pipe_args_start
= 6;
681 fail("Missing parameter for tests to run %d", argc
);
687 domain_type_string
= argv
[1];
688 session_name
= argv
[2];
689 channel_name
= argv
[3];
690 app_pid
= (pid_t
) atoi(argv
[4]);
691 app_state_file
= argv
[5];
693 if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string
)) {
694 domain_type
= LTTNG_DOMAIN_UST
;
696 if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string
)) {
697 domain_type
= LTTNG_DOMAIN_KERNEL
;
699 if (domain_type
== LTTNG_DOMAIN_NONE
) {
700 fail("Unknown domain type");
704 diag("Test trigger for domain %s with buffer_usage_low condition", domain_type_string
);
705 test_triggers_buffer_usage_condition(session_name
, channel_name
, domain_type
, LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
706 diag("Test trigger for domain %s with buffer_usage_high condition", domain_type_string
);
707 test_triggers_buffer_usage_condition(session_name
, channel_name
, domain_type
, LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
709 diag("Test notification channel api for domain %s", domain_type_string
);
710 test_notification_channel(session_name
, channel_name
, domain_type
, argv
);
712 return exit_status();