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