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