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