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