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