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