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