Fix: create lttng run dir regardless of user privilege
[lttng-tools.git] / tests / regression / tools / notification / notification.c
... / ...
CommitLineData
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 * 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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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
24 * SOFTWARE.
25 */
26
27#include <assert.h>
28#include <math.h>
29#include <stdbool.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include <inttypes.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38
39#include <lttng/action/action.h>
40#include <lttng/action/notify.h>
41#include <lttng/condition/buffer-usage.h>
42#include <lttng/condition/condition.h>
43#include <lttng/condition/evaluation.h>
44#include <lttng/domain.h>
45#include <lttng/endpoint.h>
46#include <lttng/lttng-error.h>
47#include <lttng/notification/channel.h>
48#include <lttng/notification/notification.h>
49#include <lttng/trigger/trigger.h>
50
51#include <tap/tap.h>
52
53#define NUM_TESTS 104
54int nb_args = 0;
55int named_pipe_args_start = 0;
56
57int write_pipe(const char *path, uint8_t data)
58{
59 int ret = 0;
60 int fd = 0;
61
62 fd = open(path, O_WRONLY | O_NONBLOCK);
63 if (fd < 0) {
64 perror("Could not open consumer control named pipe");
65 goto end;
66 }
67
68 ret = write(fd, &data , sizeof(data));
69 if (ret < 1) {
70 perror("Named pipe write failed");
71 if (close(fd)) {
72 perror("Named pipe close failed");
73 }
74 ret = -1;
75 goto end;
76 }
77
78 ret = close(fd);
79 if (ret < 0) {
80 perror("Name pipe closing failed");
81 ret = -1;
82 goto end;
83 }
84end:
85 return ret;
86}
87
88int stop_consumer(const char **argv)
89{
90 int ret = 0;
91 for (int i = named_pipe_args_start; i < nb_args; i++) {
92 ret = write_pipe(argv[i], 49);
93 }
94 return ret;
95}
96
97int resume_consumer(const char **argv)
98{
99 int ret = 0;
100 for (int i = named_pipe_args_start; i < nb_args; i++) {
101 ret = write_pipe(argv[i], 0);
102 }
103 return ret;
104}
105
106void test_triggers_buffer_usage_condition(const char *session_name,
107 const char *channel_name,
108 enum lttng_domain_type domain_type,
109 enum lttng_condition_type condition_type)
110{
111 enum lttng_condition_status condition_status;
112 struct lttng_action *action;
113
114 /* Set-up */
115 action = lttng_action_notify_create();
116 if (!action) {
117 fail("Setup error on action creation");
118 goto end;
119 }
120
121 /* Test lttng_register_trigger with null value */
122 ok(lttng_register_trigger(NULL) == -LTTNG_ERR_INVALID, "Registering a NULL trigger fails as expected");
123
124 /* Test: register a trigger */
125 unsigned int test_vector_size = 5;
126 for (unsigned int i = 0; i < pow(2,test_vector_size); i++) {
127 int loop_ret = 0;
128 char *test_tuple_string = NULL;
129 unsigned int mask_position = 0;
130 bool session_name_set = false;
131 bool channel_name_set = false;
132 bool threshold_ratio_set = false;
133 bool threshold_byte_set = false;
134 bool domain_type_set = false;
135
136 struct lttng_trigger *trigger = NULL;
137 struct lttng_condition *condition = NULL;
138
139 /* Create base condition */
140 switch (condition_type) {
141 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
142 condition = lttng_condition_buffer_usage_low_create();
143 break;
144 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
145 condition = lttng_condition_buffer_usage_high_create();
146 break;
147 default:
148 loop_ret = 1;
149 goto loop_end;
150 }
151
152 if (!condition) {
153 loop_ret = 1;
154 goto loop_end;
155
156 }
157
158 /* Prepare the condition for trigger registration test */
159
160 /* Set session name */
161 if ((1 << mask_position) & i) {
162 condition_status = lttng_condition_buffer_usage_set_session_name(
163 condition, session_name);
164 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
165 loop_ret = 1;
166 goto loop_end;
167 }
168 session_name_set = true;
169 }
170 mask_position++;
171
172 /* Set channel name */
173 if ((1 << mask_position) & i) {
174 condition_status = lttng_condition_buffer_usage_set_channel_name(
175 condition, channel_name);
176 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
177 loop_ret = 1;
178 goto loop_end;
179 }
180 channel_name_set = true;
181 }
182 mask_position++;
183
184 /* Set threshold ratio */
185 if ((1 << mask_position) & i) {
186 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
187 condition, 0.0);
188 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
189 loop_ret = 1;
190 goto loop_end;
191 }
192 threshold_ratio_set = true;
193 }
194 mask_position++;
195
196 /* Set threshold byte */
197 if ((1 << mask_position) & i) {
198 condition_status = lttng_condition_buffer_usage_set_threshold(
199 condition, 0);
200 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
201 loop_ret = 1;
202 goto loop_end;
203 }
204 threshold_byte_set = true;
205 }
206 mask_position++;
207
208 /* Set domain type */
209 if ((1 << mask_position) & i) {
210 condition_status = lttng_condition_buffer_usage_set_domain_type(
211 condition, LTTNG_DOMAIN_UST);
212 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
213 loop_ret = 1;
214 goto loop_end;
215 }
216 domain_type_set = true;
217 }
218
219 /* Safety check */
220 if (mask_position != test_vector_size -1) {
221 assert("Logic error for test vector generation");
222 }
223
224 loop_ret = asprintf(&test_tuple_string, "session name %s, channel name %s, threshold ratio %s, threshold byte %s, domain type %s",
225 session_name_set ? "set" : "unset",
226 channel_name_set ? "set" : "unset",
227 threshold_ratio_set ? "set" : "unset",
228 threshold_byte_set ? "set" : "unset",
229 domain_type_set? "set" : "unset");
230 if (!test_tuple_string || loop_ret < 0) {
231 loop_ret = 1;
232 goto loop_end;
233 }
234
235 /* Create trigger */
236 trigger = lttng_trigger_create(condition, action);
237 if (!trigger) {
238 loop_ret = 1;
239 goto loop_end;
240 }
241
242 loop_ret = lttng_register_trigger(trigger);
243
244loop_end:
245 if (loop_ret == 1) {
246 fail("Setup error occurred for tuple: %s", test_tuple_string);
247 goto loop_cleanup;
248 }
249
250 /* This combination happens three times */
251 if (session_name_set && channel_name_set
252 && (threshold_ratio_set || threshold_byte_set)
253 && domain_type_set) {
254 ok(loop_ret == 0, "Trigger is registered: %s", test_tuple_string);
255
256 /*
257 * Test that a trigger cannot be registered
258 * multiple time.
259 */
260 loop_ret = lttng_register_trigger(trigger);
261 ok(loop_ret == -LTTNG_ERR_TRIGGER_EXISTS, "Re-register trigger fails as expected: %s", test_tuple_string);
262
263 /* Test that a trigger can be unregistered */
264 loop_ret = lttng_unregister_trigger(trigger);
265 ok(loop_ret == 0, "Unregister trigger: %s", test_tuple_string);
266
267 /*
268 * Test that unregistration of a non-previously
269 * registered trigger fail.
270 */
271 loop_ret = lttng_unregister_trigger(trigger);
272 ok(loop_ret == -LTTNG_ERR_TRIGGER_NOT_FOUND, "Unregister of a non-registerd trigger fails as expected: %s", test_tuple_string);
273 } else {
274 ok(loop_ret == -LTTNG_ERR_INVALID_TRIGGER, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string);
275 }
276
277loop_cleanup:
278 free(test_tuple_string);
279 lttng_trigger_destroy(trigger);
280 lttng_condition_destroy(condition);
281 }
282
283end:
284 lttng_action_destroy(action);
285}
286
287void test_notification_channel(const char *session_name, const char *channel_name, enum lttng_domain_type domain_type, const char **argv)
288{
289 int ret = 0;
290 enum lttng_condition_status condition_status;
291 enum lttng_notification_channel_status nc_status;
292
293 struct lttng_action *action = NULL;
294 struct lttng_notification *notification = NULL;
295 struct lttng_notification_channel *notification_channel = NULL;
296 struct lttng_trigger *trigger = NULL;
297
298 struct lttng_condition *low_condition = NULL;
299 struct lttng_condition *high_condition = NULL;
300 struct lttng_condition *dummy_invalid_condition = NULL;
301 struct lttng_condition *dummy_condition = NULL;
302
303 double low_ratio = 0.0;
304 double high_ratio = 0.99;
305
306 /* Set-up */
307 action = lttng_action_notify_create();
308 if (!action) {
309 fail("Setup error on action creation");
310 goto end;
311 }
312
313 /* Create a dummy, empty condition for later test */
314 dummy_invalid_condition = lttng_condition_buffer_usage_low_create();
315 if (!dummy_invalid_condition) {
316 fail("Setup error on condition creation");
317 goto end;
318 }
319
320 /* Create a valid dummy condition with a ratio of 0.5 */
321 dummy_condition = lttng_condition_buffer_usage_low_create();
322 if (!dummy_condition) {
323 fail("Setup error on dummy_condition creation");
324 goto end;
325
326 }
327 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
328 dummy_condition, 0.5);
329 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
330 fail("Setup error on condition creation");
331 goto end;
332 }
333
334 condition_status = lttng_condition_buffer_usage_set_session_name(
335 dummy_condition, session_name);
336 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
337 fail("Setup error on dummy_condition creation");
338 goto end;
339 }
340 condition_status = lttng_condition_buffer_usage_set_channel_name(
341 dummy_condition, channel_name);
342 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
343 fail("Setup error on dummy_condition creation");
344 goto end;
345 }
346 condition_status = lttng_condition_buffer_usage_set_domain_type(
347 dummy_condition, domain_type);
348 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
349 fail("Setup error on dummy_condition creation");
350 goto end;
351 }
352
353 /* Register a low condition with a ratio */
354 low_condition = lttng_condition_buffer_usage_low_create();
355 if (!low_condition) {
356 fail("Setup error on low_condition creation");
357 goto end;
358 }
359 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
360 low_condition, low_ratio);
361 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
362 fail("Setup error on low_condition creation");
363 goto end;
364 }
365
366 condition_status = lttng_condition_buffer_usage_set_session_name(
367 low_condition, session_name);
368 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
369 fail("Setup error on low_condition creation");
370 goto end;
371 }
372 condition_status = lttng_condition_buffer_usage_set_channel_name(
373 low_condition, channel_name);
374 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
375 fail("Setup error on low_condition creation");
376 goto end;
377 }
378 condition_status = lttng_condition_buffer_usage_set_domain_type(
379 low_condition, domain_type);
380 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
381 fail("Setup error on low_condition creation");
382 goto end;
383
384 }
385
386 /* Register a high condition with a ratio */
387 high_condition = lttng_condition_buffer_usage_high_create();
388 if (!high_condition) {
389 fail("Setup error on high_condition creation");
390 goto end;
391 }
392
393 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
394 high_condition, high_ratio);
395 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
396 fail("Setup error on high_condition creation");
397 goto end;
398 }
399
400 condition_status = lttng_condition_buffer_usage_set_session_name(
401 high_condition, session_name);
402 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
403 fail("Setup error on high_condition creation");
404 goto end;
405 }
406 condition_status = lttng_condition_buffer_usage_set_channel_name(
407 high_condition, channel_name);
408 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
409 fail("Setup error on high_condition creation");
410 goto end;
411 }
412 condition_status = lttng_condition_buffer_usage_set_domain_type(
413 high_condition, domain_type);
414 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
415 fail("Setup error on high_condition creation");
416 goto end;
417 }
418
419 /* Register the triggers for low and high condition */
420 trigger = lttng_trigger_create(low_condition, action);
421 if (!trigger) {
422 fail("Setup error on low trigger creation");
423 goto end;
424 }
425
426 ret = lttng_register_trigger(trigger);
427 if (ret) {
428 fail("Setup error on low trigger registration");
429 goto end;
430 }
431
432 lttng_trigger_destroy(trigger);
433 trigger = NULL;
434
435 trigger = lttng_trigger_create(high_condition, action);
436 if (!trigger) {
437 fail("Setup error on high trigger creation");
438 goto end;
439 }
440
441 ret = lttng_register_trigger(trigger);
442 if (ret) {
443 fail("Setup error on high trigger registration");
444 goto end;
445 }
446
447 /* Begin testing */
448 notification_channel = lttng_notification_channel_create(lttng_session_daemon_notification_endpoint);
449 ok(notification_channel, "Notification channel object creation");
450 if (!notification_channel) {
451 goto end;
452 }
453
454 /* Basic error path check */
455 nc_status = lttng_notification_channel_subscribe(NULL, NULL);
456 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID, "Notification channel subscription is invalid: NULL, NULL");
457
458 nc_status = lttng_notification_channel_subscribe(notification_channel, NULL);
459 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID, "Notification channel subscription is invalid: NON-NULL, NULL");
460
461 nc_status = lttng_notification_channel_subscribe(NULL, low_condition);
462 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID, "Notification channel subscription is invalid: NULL, NON-NULL");
463
464 nc_status = lttng_notification_channel_subscribe(notification_channel, dummy_invalid_condition);
465 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID, "Subscribing to an invalid condition");
466
467 nc_status = lttng_notification_channel_unsubscribe(notification_channel, dummy_invalid_condition);
468 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID, "Unsubscribing to an invalid condition");
469
470 nc_status = lttng_notification_channel_unsubscribe(notification_channel, dummy_condition);
471 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION, "Unsubscribing to an valid unknown condition");
472
473 /* Subscribe a valid low condition */
474 nc_status = lttng_notification_channel_subscribe(notification_channel, low_condition);
475 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK, "Subscribe to condition");
476
477 /* Subscribe a valid high condition */
478 nc_status = lttng_notification_channel_subscribe(notification_channel, high_condition);
479 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK, "Subscribe to condition");
480
481 nc_status = lttng_notification_channel_subscribe(notification_channel, low_condition);
482 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED, "Subscribe to a condition for which subscription was already done");
483
484 nc_status = lttng_notification_channel_subscribe(notification_channel, high_condition);
485 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED, "Subscribe to a condition for which subscription was already done");
486
487 /* Wait for notification to happen */
488 lttng_start_tracing(session_name);
489 stop_consumer(argv);
490
491 /* Wait for high notification */
492 nc_status = lttng_notification_channel_get_next_notification(notification_channel, &notification);
493 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
494 && notification
495 && lttng_condition_get_type(lttng_notification_get_condition(notification)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
496 "High notification received after intermediary communication");
497 lttng_notification_destroy(notification);
498 notification = NULL;
499
500 resume_consumer(argv);
501 lttng_stop_tracing(session_name);
502
503 /*
504 * Test that communication still work even if there is notification
505 * waiting for consumption.
506 */
507
508 nc_status = lttng_notification_channel_unsubscribe(notification_channel, low_condition);
509 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK, "Unsubscribe with pending notification");
510
511 nc_status = lttng_notification_channel_subscribe(notification_channel, low_condition);
512 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK, "subscribe with pending notification");
513
514 nc_status = lttng_notification_channel_get_next_notification(notification_channel, &notification);
515 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK
516 && notification
517 && lttng_condition_get_type(lttng_notification_get_condition(notification)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
518 "Low notification received after intermediary communication");
519 lttng_notification_destroy(notification);
520 notification = NULL;
521
522 /* Stop consumer to force a high notification */
523 lttng_start_tracing(session_name);
524 stop_consumer(argv);
525
526 nc_status = lttng_notification_channel_get_next_notification(notification_channel, &notification);
527 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
528 lttng_condition_get_type(lttng_notification_get_condition(notification)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
529 "High notification received after intermediary communication");
530 lttng_notification_destroy(notification);
531 notification = NULL;
532
533 /* Resume consumer to allow event consumption */
534 resume_consumer(argv);
535 lttng_stop_tracing(session_name);
536
537 nc_status = lttng_notification_channel_get_next_notification(notification_channel, &notification);
538 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
539 lttng_condition_get_type(lttng_notification_get_condition(notification)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
540 "Low notification received after re-subscription");
541 lttng_notification_destroy(notification);
542 notification = NULL;
543
544 /* Stop consumer to force a high notification */
545 lttng_start_tracing(session_name);
546 stop_consumer(argv);
547
548 nc_status = lttng_notification_channel_get_next_notification(notification_channel, &notification);
549 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
550 lttng_condition_get_type(lttng_notification_get_condition(notification)) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
551 "High notification");
552 lttng_notification_destroy(notification);
553 notification = NULL;
554
555 /* Resume consumer to allow event consumption */
556 resume_consumer(argv);
557 lttng_stop_tracing(session_name);
558
559 nc_status = lttng_notification_channel_unsubscribe(notification_channel, low_condition);
560 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK, "Unsubscribe low condition with pending notification");
561 nc_status = lttng_notification_channel_unsubscribe(notification_channel, high_condition);
562 ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK, "Unsubscribe high condition with pending notification");
563
564end:
565 lttng_notification_channel_destroy(notification_channel);
566 lttng_trigger_destroy(trigger);
567 lttng_action_destroy(action);
568 lttng_condition_destroy(low_condition);
569 lttng_condition_destroy(high_condition);
570 lttng_condition_destroy(dummy_invalid_condition);
571 lttng_condition_destroy(dummy_condition);
572}
573
574int main(int argc, const char *argv[])
575{
576 const char *session_name = NULL;
577 const char *channel_name = NULL;
578 const char *domain_type_string = NULL;
579 enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
580
581 plan_tests(NUM_TESTS);
582
583 /* Argument 4 and upward are named pipe location for consumerd control */
584 named_pipe_args_start = 4;
585
586 if (argc < 5) {
587 fail("Missing parameter for tests to run %d", argc);
588 goto error;
589 }
590
591 nb_args = argc;
592
593 session_name = argv[1];
594 channel_name = argv[2];
595 domain_type_string= argv[3];
596
597 if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string)) {
598 domain_type = LTTNG_DOMAIN_UST;
599 }
600 if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
601 domain_type = LTTNG_DOMAIN_KERNEL;
602 }
603 if (domain_type == LTTNG_DOMAIN_NONE) {
604 fail("Unknown domain type");
605 goto error;
606 }
607
608 diag("Test trigger for domain %s with buffer_usage_low condition", domain_type_string);
609 test_triggers_buffer_usage_condition(session_name, channel_name, domain_type, LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
610 diag("Test trigger for domain %s with buffer_usage_high condition", domain_type_string);
611 test_triggers_buffer_usage_condition(session_name, channel_name, domain_type, LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
612
613 diag("Test notification channel api for domain %s", domain_type_string);
614 test_notification_channel(session_name, channel_name, domain_type, argv);
615error:
616 return exit_status();
617}
618
This page took 0.02451 seconds and 4 git commands to generate.