Tests: Add test to check shared-memory FD leaks after relayd dies
[lttng-tools.git] / tests / regression / tools / notification / base_client.c
1 /*
2 * base_client.c
3 *
4 * Base client application for testing of LTTng notification API
5 *
6 * Copyright 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
7 *
8 * SPDX-License-Identifier: MIT
9 *
10 */
11
12 #include <lttng/action/action.h>
13 #include <lttng/action/list.h>
14 #include <lttng/action/notify.h>
15 #include <lttng/condition/buffer-usage.h>
16 #include <lttng/condition/condition.h>
17 #include <lttng/condition/evaluation.h>
18 #include <lttng/domain.h>
19 #include <lttng/endpoint.h>
20 #include <lttng/lttng-error.h>
21 #include <lttng/notification/channel.h>
22 #include <lttng/notification/notification.h>
23 #include <lttng/trigger/trigger.h>
24
25 #include <inttypes.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 static unsigned int nr_notifications = 0;
32 static unsigned int nr_expected_notifications = 0;
33 static const char *session_name = NULL;
34 static const char *channel_name = NULL;
35 static double threshold_ratio = 0.0;
36 static uint64_t threshold_bytes = 0;
37 static bool is_threshold_ratio = false;
38 static bool use_action_list = false;
39 static enum lttng_condition_type buffer_usage_type = LTTNG_CONDITION_TYPE_UNKNOWN;
40 static enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
41
42 int handle_condition(const struct lttng_condition *condition,
43 const struct lttng_evaluation *condition_evaluation);
44
45 static int parse_arguments(char **argv)
46 {
47 int sscanf_ret;
48 const char *domain_type_string = NULL;
49 const char *buffer_usage_type_string = NULL;
50 const char *buffer_usage_threshold_type = NULL;
51 const char *buffer_usage_threshold_value = NULL;
52 const char *nr_expected_notifications_string = NULL;
53 const char *use_action_list_value = NULL;
54
55 session_name = argv[1];
56 channel_name = argv[2];
57 domain_type_string = argv[3];
58 buffer_usage_type_string = argv[4];
59 buffer_usage_threshold_type = argv[5];
60 buffer_usage_threshold_value = argv[6];
61 nr_expected_notifications_string = argv[7];
62 use_action_list_value = argv[8];
63
64 /* Parse arguments */
65 /* Domain type */
66 if (!strcasecmp("LTTNG_DOMAIN_UST", domain_type_string)) {
67 domain_type = LTTNG_DOMAIN_UST;
68 }
69 if (!strcasecmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
70 domain_type = LTTNG_DOMAIN_KERNEL;
71 }
72 if (domain_type == LTTNG_DOMAIN_NONE) {
73 printf("error: Unknown domain type\n");
74 goto error;
75 }
76
77 /* Buffer usage condition type */
78 if (!strcasecmp("low", buffer_usage_type_string)) {
79 buffer_usage_type = LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW;
80 }
81 if (!strcasecmp("high", buffer_usage_type_string)) {
82 buffer_usage_type = LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH;
83 }
84 if (buffer_usage_type == LTTNG_CONDITION_TYPE_UNKNOWN) {
85 printf("error: Unknown condition type\n");
86 goto error;
87 }
88
89 /* Ratio or bytes ? */
90 if (!strcasecmp("bytes", buffer_usage_threshold_type)) {
91 is_threshold_ratio = false;
92 sscanf_ret = sscanf(buffer_usage_threshold_value, "%" SCNu64, &threshold_bytes);
93 if (sscanf_ret != 1) {
94 printf("error: Invalid buffer usage threshold value bytes (integer), sscanf returned %d\n",
95 sscanf_ret);
96 goto error;
97 }
98 }
99
100 if (!strcasecmp("ratio", buffer_usage_threshold_type)) {
101 is_threshold_ratio = true;
102 sscanf_ret = sscanf(buffer_usage_threshold_value, "%lf", &threshold_ratio);
103 if (sscanf_ret != 1) {
104 printf("error: Invalid buffer usage threshold value ratio (float), sscanf returned %d\n",
105 sscanf_ret);
106 goto error;
107 }
108 }
109
110 /* Number of notification to expect */
111 sscanf_ret = sscanf(nr_expected_notifications_string, "%d", &nr_expected_notifications);
112 if (sscanf_ret != 1) {
113 printf("error: Invalid nr_expected_notifications, sscanf returned %d\n",
114 sscanf_ret);
115 goto error;
116 }
117
118 /* Put notify action in a group. */
119 if (!strcasecmp("1", use_action_list_value)) {
120 use_action_list = true;
121 }
122
123 return 0;
124 error:
125 return 1;
126 }
127
128 int main(int argc, char **argv)
129 {
130 int ret = 0;
131 enum lttng_condition_status condition_status;
132 enum lttng_action_status action_status;
133 enum lttng_notification_channel_status nc_status;
134 struct lttng_notification_channel *notification_channel = NULL;
135 struct lttng_condition *condition = NULL;
136 struct lttng_action *action = NULL;
137 struct lttng_trigger *trigger = NULL;
138 enum lttng_error_code ret_code;
139
140 /*
141 * Disable buffering on stdout.
142 * Safety measure to prevent hang on the validation side since
143 * stdout is used for outside synchronization.
144 */
145 setbuf(stdout, NULL);
146
147 if (argc < 9) {
148 printf("error: Missing arguments for tests\n");
149 ret = 1;
150 goto end;
151 }
152
153 ret = parse_arguments(argv);
154 if (ret) {
155 printf("error: Could not parse arguments\n");
156 goto end;
157 }
158
159 /* Setup */
160 notification_channel =
161 lttng_notification_channel_create(lttng_session_daemon_notification_endpoint);
162 if (!notification_channel) {
163 printf("error: Could not create notification channel\n");
164 ret = 1;
165 goto end;
166 }
167
168 switch (buffer_usage_type) {
169 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
170 condition = lttng_condition_buffer_usage_low_create();
171 break;
172 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
173 condition = lttng_condition_buffer_usage_high_create();
174 break;
175 default:
176 printf("error: Invalid buffer_usage_type\n");
177 ret = 1;
178 goto end;
179 }
180
181 if (!condition) {
182 printf("error: Could not create condition object\n");
183 ret = 1;
184 goto end;
185 }
186
187 if (is_threshold_ratio) {
188 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
189 condition, threshold_ratio);
190 } else {
191 condition_status =
192 lttng_condition_buffer_usage_set_threshold(condition, threshold_bytes);
193 }
194
195 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
196 printf("error: Could not set threshold\n");
197 ret = 1;
198 goto end;
199 }
200
201 condition_status = lttng_condition_buffer_usage_set_session_name(condition, session_name);
202 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
203 printf("error: Could not set session name\n");
204 ret = 1;
205 goto end;
206 }
207 condition_status = lttng_condition_buffer_usage_set_channel_name(condition, channel_name);
208 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
209 printf("error: Could not set channel name\n");
210 ret = 1;
211 goto end;
212 }
213 condition_status = lttng_condition_buffer_usage_set_domain_type(condition, domain_type);
214 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
215 printf("error: Could not set domain type\n");
216 ret = 1;
217 goto end;
218 }
219
220 if (use_action_list) {
221 struct lttng_action *notify, *group;
222
223 group = lttng_action_list_create();
224 if (!group) {
225 printf("error: Could not create action list\n");
226 ret = 1;
227 goto end;
228 }
229
230 notify = lttng_action_notify_create();
231 if (!notify) {
232 lttng_action_destroy(group);
233 printf("error: Could not create action notify\n");
234 ret = 1;
235 goto end;
236 }
237
238 action_status = lttng_action_list_add_action(group, notify);
239 if (action_status != LTTNG_ACTION_STATUS_OK) {
240 printf("error: Could not add action notify to action list\n");
241 lttng_action_destroy(group);
242 lttng_action_destroy(notify);
243 ret = 1;
244 goto end;
245 }
246
247 action = group;
248 } else {
249 action = lttng_action_notify_create();
250 if (!action) {
251 printf("error: Could not create action notify\n");
252 ret = 1;
253 goto end;
254 }
255 }
256
257 trigger = lttng_trigger_create(condition, action);
258 if (!trigger) {
259 printf("error: Could not create trigger\n");
260 ret = 1;
261 goto end;
262 }
263
264 ret_code = lttng_register_trigger_with_automatic_name(trigger);
265
266 /*
267 * An equivalent trigger might already be registered if an other app
268 * registered an equivalent trigger.
269 */
270 if (ret_code != LTTNG_OK && ret_code != LTTNG_ERR_TRIGGER_EXISTS) {
271 printf("error: %s\n", lttng_strerror(-ret_code));
272 ret = 1;
273 goto end;
274 }
275
276 nc_status = lttng_notification_channel_subscribe(notification_channel, condition);
277 if (nc_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
278 printf("error: Could not subscribe\n");
279 ret = 1;
280 goto end;
281 }
282
283 /* Tell outside process that the client is ready */
284 printf("sync: ready\n");
285
286 for (;;) {
287 struct lttng_notification *notification;
288 enum lttng_notification_channel_status status;
289 const struct lttng_evaluation *notification_evaluation;
290 const struct lttng_condition *notification_condition;
291
292 if (nr_notifications == nr_expected_notifications) {
293 ret = 0;
294 goto end;
295 }
296 /* Receive the next notification. */
297 status = lttng_notification_channel_get_next_notification(notification_channel,
298 &notification);
299
300 switch (status) {
301 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
302 break;
303 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
304 ret = 1;
305 printf("error: No drop should be observed during this test app\n");
306 goto end;
307 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
308 /*
309 * The notification channel has been closed by the
310 * session daemon. This is typically caused by a session
311 * daemon shutting down (cleanly or because of a crash).
312 */
313 printf("error: Notification channel was closed\n");
314 ret = 1;
315 goto end;
316 default:
317 /* Unhandled conditions / errors. */
318 printf("error: Unknown notification channel status (%d) \n", status);
319 ret = 1;
320 goto end;
321 }
322
323 notification_condition = lttng_notification_get_condition(notification);
324 notification_evaluation = lttng_notification_get_evaluation(notification);
325
326 ret = handle_condition(notification_condition, notification_evaluation);
327 nr_notifications++;
328
329 lttng_notification_destroy(notification);
330 if (ret != 0) {
331 goto end;
332 }
333 }
334 end:
335 if (trigger) {
336 lttng_unregister_trigger(trigger);
337 }
338 if (lttng_notification_channel_unsubscribe(notification_channel, condition)) {
339 printf("error: channel unsubscribe error\n");
340 }
341 lttng_trigger_destroy(trigger);
342 lttng_condition_destroy(condition);
343 lttng_action_destroy(action);
344 lttng_notification_channel_destroy(notification_channel);
345 printf("exit: %d\n", ret);
346 return ret;
347 }
348
349 int handle_condition(const struct lttng_condition *condition,
350 const struct lttng_evaluation *evaluation)
351 {
352 int ret = 0;
353 const char *string_low = "low";
354 const char *string_high = "high";
355 const char *string_condition_type = NULL;
356 const char *condition_session_name = NULL;
357 const char *condition_channel_name = NULL;
358 enum lttng_condition_type condition_type;
359 enum lttng_domain_type condition_domain_type;
360 double buffer_usage_ratio;
361 uint64_t buffer_usage_bytes;
362
363 condition_type = lttng_condition_get_type(condition);
364
365 if (condition_type != buffer_usage_type) {
366 ret = 1;
367 printf("error: condition type and buffer usage type are not the same\n");
368 goto end;
369 }
370
371 /* Fetch info to test */
372 ret = lttng_condition_buffer_usage_get_session_name(condition, &condition_session_name);
373 if (ret) {
374 printf("error: session name could not be fetched\n");
375 ret = 1;
376 goto end;
377 }
378 ret = lttng_condition_buffer_usage_get_channel_name(condition, &condition_channel_name);
379 if (ret) {
380 printf("error: channel name could not be fetched\n");
381 ret = 1;
382 goto end;
383 }
384 ret = lttng_condition_buffer_usage_get_domain_type(condition, &condition_domain_type);
385 if (ret) {
386 printf("error: domain type could not be fetched\n");
387 ret = 1;
388 goto end;
389 }
390
391 if (strcmp(condition_session_name, session_name) != 0) {
392 printf("error: session name differs\n");
393 ret = 1;
394 goto end;
395 }
396
397 if (strcmp(condition_channel_name, channel_name) != 0) {
398 printf("error: channel name differs\n");
399 ret = 1;
400 goto end;
401 }
402
403 if (condition_domain_type != domain_type) {
404 printf("error: domain type differs\n");
405 ret = 1;
406 goto end;
407 }
408
409 if (is_threshold_ratio) {
410 lttng_evaluation_buffer_usage_get_usage_ratio(evaluation, &buffer_usage_ratio);
411 switch (condition_type) {
412 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
413 if (buffer_usage_ratio > threshold_ratio) {
414 printf("error: buffer usage ratio is bigger than set threshold ratio\n");
415 ret = 1;
416 goto end;
417 }
418 break;
419 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
420 if (buffer_usage_ratio < threshold_ratio) {
421 printf("error: buffer usage ratio is lower than set threshold ratio\n");
422 ret = 1;
423 goto end;
424 }
425 break;
426 default:
427 printf("error: Unknown condition type\n");
428 ret = 1;
429 goto end;
430 }
431 } else {
432 lttng_evaluation_buffer_usage_get_usage(evaluation, &buffer_usage_bytes);
433 switch (condition_type) {
434 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
435 if (buffer_usage_bytes > threshold_bytes) {
436 printf("error: buffer usage ratio is bigger than set threshold bytes\n");
437 ret = 1;
438 goto end;
439 }
440 break;
441 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
442 if (buffer_usage_bytes < threshold_bytes) {
443 printf("error: buffer usage ratio is lower than set threshold bytes\n");
444 ret = 1;
445 goto end;
446 }
447 break;
448 default:
449 printf("error: Unknown condition type\n");
450 ret = 1;
451 goto end;
452 }
453 }
454
455 switch (condition_type) {
456 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
457 string_condition_type = string_low;
458 break;
459 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
460 string_condition_type = string_high;
461 break;
462 default:
463 printf("error: Unknown condition type\n");
464 ret = 1;
465 goto end;
466 }
467
468 printf("notification: %s %d\n", string_condition_type, nr_notifications);
469 end:
470 return ret;
471 }
This page took 0.03975 seconds and 5 git commands to generate.