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