4 * Tests suite for LTTng notification API
6 * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 #include <sys/types.h>
42 #include <lttng/action/action.h>
43 #include <lttng/action/notify.h>
44 #include <lttng/condition/buffer-usage.h>
45 #include <lttng/condition/condition.h>
46 #include <lttng/condition/evaluation.h>
47 #include <lttng/domain.h>
48 #include <lttng/endpoint.h>
49 #include <lttng/lttng-error.h>
50 #include <lttng/notification/channel.h>
51 #include <lttng/notification/notification.h>
52 #include <lttng/trigger/trigger.h>
53 #include <lttng/lttng.h>
60 int named_pipe_args_start
= 0;
62 const char *app_state_file
= NULL
;
65 void wait_on_file(const char *path
, bool file_exist
)
74 ret
= stat(path
, &buf
);
75 if (ret
== -1 && errno
== ENOENT
) {
78 * The file does not exist. wait a bit and
79 * continue looping until it does.
81 (void) poll(NULL
, 0, 10);
86 * File does not exist and the exit condition we want.
87 * Break from the loop and return.
96 * stat() returned 0, so the file exists. break now only if
97 * that's the exit condition we want.
105 int write_pipe(const char *path
, uint8_t data
)
110 fd
= open(path
, O_WRONLY
| O_NONBLOCK
);
112 perror("Could not open consumer control named pipe");
116 ret
= write(fd
, &data
, sizeof(data
));
118 perror("Named pipe write failed");
120 perror("Named pipe close failed");
128 perror("Name pipe closing failed");
136 int stop_consumer(const char **argv
)
139 for (int i
= named_pipe_args_start
; i
< nb_args
; i
++) {
140 ret
= write_pipe(argv
[i
], 49);
145 int resume_consumer(const char **argv
)
148 for (int i
= named_pipe_args_start
; i
< nb_args
; i
++) {
149 ret
= write_pipe(argv
[i
], 0);
154 int suspend_application()
159 if (!stat(app_state_file
, &buf
)) {
160 fail("App is already in a suspended state.");
166 * Send SIGUSR1 to application instructing it to bypass tracepoint.
168 ret
= kill(app_pid
, SIGUSR1
);
170 fail("SIGUSR1 failed. errno %d", errno
);
175 wait_on_file(app_state_file
, true);
182 int resume_application()
187 ret
= stat(app_state_file
, &buf
);
188 if (ret
== -1 && errno
== ENOENT
) {
189 fail("State file does not exist");
197 ret
= kill(app_pid
, SIGUSR1
);
199 fail("SIGUSR1 failed. errno %d", errno
);
204 wait_on_file(app_state_file
, false);
212 void test_triggers_buffer_usage_condition(const char *session_name
,
213 const char *channel_name
,
214 enum lttng_domain_type domain_type
,
215 enum lttng_condition_type condition_type
)
217 enum lttng_condition_status condition_status
;
218 struct lttng_action
*action
;
221 action
= lttng_action_notify_create();
223 fail("Setup error on action creation");
227 /* Test lttng_register_trigger with null value */
228 ok(lttng_register_trigger(NULL
) == -LTTNG_ERR_INVALID
, "Registering a NULL trigger fails as expected");
230 /* Test: register a trigger */
231 unsigned int test_vector_size
= 5;
232 for (unsigned int i
= 0; i
< pow(2,test_vector_size
); i
++) {
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;
242 struct lttng_trigger
*trigger
= NULL
;
243 struct lttng_condition
*condition
= NULL
;
245 /* Create base condition */
246 switch (condition_type
) {
247 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
:
248 condition
= lttng_condition_buffer_usage_low_create();
250 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
:
251 condition
= lttng_condition_buffer_usage_high_create();
264 /* Prepare the condition for trigger registration test */
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
) {
274 session_name_set
= true;
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
) {
286 channel_name_set
= true;
290 /* Set threshold ratio */
291 if ((1 << mask_position
) & i
) {
292 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
294 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
298 threshold_ratio_set
= true;
302 /* Set threshold byte */
303 if ((1 << mask_position
) & i
) {
304 condition_status
= lttng_condition_buffer_usage_set_threshold(
306 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
310 threshold_byte_set
= true;
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
) {
322 domain_type_set
= true;
326 if (mask_position
!= test_vector_size
-1) {
327 assert("Logic error for test vector generation");
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) {
342 trigger
= lttng_trigger_create(condition
, action
);
348 loop_ret
= lttng_register_trigger(trigger
);
352 fail("Setup error occurred for tuple: %s", test_tuple_string
);
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
);
363 * Test that a trigger cannot be registered
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
);
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
);
374 * Test that unregistration of a non-previously
375 * registered trigger fail.
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
);
380 ok(loop_ret
== -LTTNG_ERR_INVALID_TRIGGER
, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string
);
384 free(test_tuple_string
);
385 lttng_trigger_destroy(trigger
);
386 lttng_condition_destroy(condition
);
390 lttng_action_destroy(action
);
394 void wait_data_pending(const char *session_name
)
399 ret
= lttng_data_pending(session_name
);
404 void test_notification_channel(const char *session_name
, const char *channel_name
, const enum lttng_domain_type domain_type
, const char **argv
)
407 enum lttng_condition_status condition_status
;
408 enum lttng_notification_channel_status nc_status
;
410 struct lttng_action
*action
= NULL
;
411 struct lttng_notification
*notification
= NULL
;
412 struct lttng_notification_channel
*notification_channel
= NULL
;
413 struct lttng_trigger
*trigger
= NULL
;
415 struct lttng_condition
*low_condition
= NULL
;
416 struct lttng_condition
*high_condition
= NULL
;
417 struct lttng_condition
*dummy_invalid_condition
= NULL
;
418 struct lttng_condition
*dummy_condition
= NULL
;
420 double low_ratio
= 0.0;
421 double high_ratio
= 0.99;
424 action
= lttng_action_notify_create();
426 fail("Setup error on action creation");
430 /* Create a dummy, empty condition for later test */
431 dummy_invalid_condition
= lttng_condition_buffer_usage_low_create();
432 if (!dummy_invalid_condition
) {
433 fail("Setup error on condition creation");
437 /* Create a valid dummy condition with a ratio of 0.5 */
438 dummy_condition
= lttng_condition_buffer_usage_low_create();
439 if (!dummy_condition
) {
440 fail("Setup error on dummy_condition creation");
444 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
445 dummy_condition
, 0.5);
446 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
447 fail("Setup error on condition creation");
451 condition_status
= lttng_condition_buffer_usage_set_session_name(
452 dummy_condition
, session_name
);
453 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
454 fail("Setup error on dummy_condition creation");
457 condition_status
= lttng_condition_buffer_usage_set_channel_name(
458 dummy_condition
, channel_name
);
459 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
460 fail("Setup error on dummy_condition creation");
463 condition_status
= lttng_condition_buffer_usage_set_domain_type(
464 dummy_condition
, domain_type
);
465 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
466 fail("Setup error on dummy_condition creation");
470 /* Register a low condition with a ratio */
471 low_condition
= lttng_condition_buffer_usage_low_create();
472 if (!low_condition
) {
473 fail("Setup error on low_condition creation");
476 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
477 low_condition
, low_ratio
);
478 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
479 fail("Setup error on low_condition creation");
483 condition_status
= lttng_condition_buffer_usage_set_session_name(
484 low_condition
, session_name
);
485 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
486 fail("Setup error on low_condition creation");
489 condition_status
= lttng_condition_buffer_usage_set_channel_name(
490 low_condition
, channel_name
);
491 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
492 fail("Setup error on low_condition creation");
495 condition_status
= lttng_condition_buffer_usage_set_domain_type(
496 low_condition
, domain_type
);
497 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
498 fail("Setup error on low_condition creation");
503 /* Register a high condition with a ratio */
504 high_condition
= lttng_condition_buffer_usage_high_create();
505 if (!high_condition
) {
506 fail("Setup error on high_condition creation");
510 condition_status
= lttng_condition_buffer_usage_set_threshold_ratio(
511 high_condition
, high_ratio
);
512 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
513 fail("Setup error on high_condition creation");
517 condition_status
= lttng_condition_buffer_usage_set_session_name(
518 high_condition
, session_name
);
519 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
520 fail("Setup error on high_condition creation");
523 condition_status
= lttng_condition_buffer_usage_set_channel_name(
524 high_condition
, channel_name
);
525 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
526 fail("Setup error on high_condition creation");
529 condition_status
= lttng_condition_buffer_usage_set_domain_type(
530 high_condition
, domain_type
);
531 if (condition_status
!= LTTNG_CONDITION_STATUS_OK
) {
532 fail("Setup error on high_condition creation");
536 /* Register the triggers for low and high condition */
537 trigger
= lttng_trigger_create(low_condition
, action
);
539 fail("Setup error on low trigger creation");
543 ret
= lttng_register_trigger(trigger
);
545 fail("Setup error on low trigger registration");
549 lttng_trigger_destroy(trigger
);
552 trigger
= lttng_trigger_create(high_condition
, action
);
554 fail("Setup error on high trigger creation");
558 ret
= lttng_register_trigger(trigger
);
560 fail("Setup error on high trigger registration");
565 notification_channel
= lttng_notification_channel_create(lttng_session_daemon_notification_endpoint
);
566 ok(notification_channel
, "Notification channel object creation");
567 if (!notification_channel
) {
571 /* Basic error path check */
572 nc_status
= lttng_notification_channel_subscribe(NULL
, NULL
);
573 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Notification channel subscription is invalid: NULL, NULL");
575 nc_status
= lttng_notification_channel_subscribe(notification_channel
, NULL
);
576 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Notification channel subscription is invalid: NON-NULL, NULL");
578 nc_status
= lttng_notification_channel_subscribe(NULL
, low_condition
);
579 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Notification channel subscription is invalid: NULL, NON-NULL");
581 nc_status
= lttng_notification_channel_subscribe(notification_channel
, dummy_invalid_condition
);
582 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Subscribing to an invalid condition");
584 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, dummy_invalid_condition
);
585 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID
, "Unsubscribing from an invalid condition");
587 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, dummy_condition
);
588 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION
, "Unsubscribing from a valid unknown condition");
590 /* Subscribe a valid low condition */
591 nc_status
= lttng_notification_channel_subscribe(notification_channel
, low_condition
);
592 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Subscribe to condition");
594 /* Subscribe a valid high condition */
595 nc_status
= lttng_notification_channel_subscribe(notification_channel
, high_condition
);
596 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Subscribe to condition");
598 nc_status
= lttng_notification_channel_subscribe(notification_channel
, low_condition
);
599 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED
, "Subscribe to a condition for which subscription was already done");
601 nc_status
= lttng_notification_channel_subscribe(notification_channel
, high_condition
);
602 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED
, "Subscribe to a condition for which subscription was already done");
604 /* Wait for notification to happen */
606 lttng_start_tracing(session_name
);
608 /* Wait for high notification */
610 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
611 } while (nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED
);
612 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
614 && lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
,
615 "High notification received after intermediary communication");
616 lttng_notification_destroy(notification
);
619 suspend_application();
620 lttng_stop_tracing_no_wait(session_name
);
621 resume_consumer(argv
);
622 wait_data_pending(session_name
);
625 * Test that communication still work even if there is notification
626 * waiting for consumption.
629 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, low_condition
);
630 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Unsubscribe with pending notification");
632 nc_status
= lttng_notification_channel_subscribe(notification_channel
, low_condition
);
633 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "subscribe with pending notification");
636 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
637 } while (nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED
);
638 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
640 && lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
,
641 "Low notification received after intermediary communication");
642 lttng_notification_destroy(notification
);
645 /* Stop consumer to force a high notification */
647 resume_application();
648 lttng_start_tracing(session_name
);
651 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
652 } while (nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED
);
653 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
&& notification
&&
654 lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
,
655 "High notification received after intermediary communication");
656 lttng_notification_destroy(notification
);
659 suspend_application();
660 lttng_stop_tracing_no_wait(session_name
);
661 resume_consumer(argv
);
662 wait_data_pending(session_name
);
665 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
666 } while (nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED
);
667 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
&& notification
&&
668 lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
,
669 "Low notification received after re-subscription");
670 lttng_notification_destroy(notification
);
674 resume_application();
675 /* Stop consumer to force a high notification */
676 lttng_start_tracing(session_name
);
679 nc_status
= lttng_notification_channel_get_next_notification(notification_channel
, ¬ification
);
680 } while (nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED
);
681 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
&& notification
&&
682 lttng_condition_get_type(lttng_notification_get_condition(notification
)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
,
683 "High notification");
684 lttng_notification_destroy(notification
);
687 /* Resume consumer to allow event consumption */
688 suspend_application();
689 lttng_stop_tracing_no_wait(session_name
);
690 resume_consumer(argv
);
691 wait_data_pending(session_name
);
693 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, low_condition
);
694 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Unsubscribe low condition with pending notification");
695 nc_status
= lttng_notification_channel_unsubscribe(notification_channel
, high_condition
);
696 ok(nc_status
== LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
, "Unsubscribe high condition with pending notification");
699 lttng_notification_channel_destroy(notification_channel
);
700 lttng_trigger_destroy(trigger
);
701 lttng_action_destroy(action
);
702 lttng_condition_destroy(low_condition
);
703 lttng_condition_destroy(high_condition
);
704 lttng_condition_destroy(dummy_invalid_condition
);
705 lttng_condition_destroy(dummy_condition
);
708 int main(int argc
, const char *argv
[])
710 const char *session_name
= NULL
;
711 const char *channel_name
= NULL
;
712 const char *domain_type_string
= NULL
;
713 enum lttng_domain_type domain_type
= LTTNG_DOMAIN_NONE
;
715 plan_tests(NUM_TESTS
);
717 /* Argument 6 and upward are named pipe location for consumerd control */
718 named_pipe_args_start
= 6;
721 fail("Missing parameter for tests to run %d", argc
);
727 domain_type_string
= argv
[1];
728 session_name
= argv
[2];
729 channel_name
= argv
[3];
730 app_pid
= (pid_t
) atoi(argv
[4]);
731 app_state_file
= argv
[5];
733 if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string
)) {
734 domain_type
= LTTNG_DOMAIN_UST
;
736 if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string
)) {
737 domain_type
= LTTNG_DOMAIN_KERNEL
;
739 if (domain_type
== LTTNG_DOMAIN_NONE
) {
740 fail("Unknown domain type");
744 diag("Test trigger for domain %s with buffer_usage_low condition", domain_type_string
);
745 test_triggers_buffer_usage_condition(session_name
, channel_name
, domain_type
, LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
746 diag("Test trigger for domain %s with buffer_usage_high condition", domain_type_string
);
747 test_triggers_buffer_usage_condition(session_name
, channel_name
, domain_type
, LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
749 diag("Test notification channel api for domain %s", domain_type_string
);
750 test_notification_channel(session_name
, channel_name
, domain_type
, argv
);
752 return exit_status();