Tests: regression testing for notification API
[lttng-tools.git] / tests / regression / tools / notification / base_client.c
CommitLineData
434f8068
JR
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
45static unsigned int nr_notifications = 0;
46static unsigned int nr_expected_notifications = 0;
47static const char *session_name = NULL;
48static const char *channel_name = NULL;
49static double threshold_ratio = 0.0;
50static uint64_t threshold_bytes = 0;
51static bool is_threshold_ratio = false;
52static enum lttng_condition_type buffer_usage_type = LTTNG_CONDITION_TYPE_UNKNOWN;
53static enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
54
55int handle_condition(
56 const struct lttng_condition *condition,
57 const struct lttng_evaluation *condition_evaluation);
58
59int 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;
114error:
115 return 1;
116}
117
118int 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, LTTNG_DOMAIN_UST);
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 }
296end:
297 if (trigger) {
298 lttng_unregister_trigger(trigger);
299 }
300 lttng_notification_channel_unsubscribe(notification_channel, condition);
301 lttng_trigger_destroy(trigger);
302 lttng_condition_destroy(condition);
303 lttng_action_destroy(action);
304 lttng_notification_channel_destroy(notification_channel);
305 printf("exit: %d\n", ret);
306 return ret;
307}
308
309int handle_condition(
310 const struct lttng_condition *condition,
311 const struct lttng_evaluation *evaluation)
312{
313 int ret = 0;
314 const char *string_low = "low";
315 const char *string_high = "high";
316 const char *string_condition_type = NULL;
317 const char *condition_session_name = NULL;
318 const char *condition_channel_name = NULL;
319 enum lttng_condition_type condition_type;
320 enum lttng_domain_type condition_domain_type;
321 double buffer_usage_ratio;
322 uint64_t buffer_usage_bytes;
323
324 condition_type = lttng_condition_get_type(condition);
325
326 if (condition_type != buffer_usage_type) {
327 ret = 1;
328 printf("error: condition type and buffer usage type are not the same\n");
329 goto end;
330 }
331
332 /* Fetch info to test */
333 lttng_condition_buffer_usage_get_session_name(condition,
334 &condition_session_name);
335 lttng_condition_buffer_usage_get_channel_name(condition,
336 &condition_channel_name);
337 lttng_condition_buffer_usage_get_domain_type(condition,
338 &condition_domain_type);
339
340 if (strcmp(condition_session_name, session_name) != 0) {
341 printf("error: session name differs\n");
342 ret = 1;
343 goto end;
344 }
345
346 if (strcmp(condition_channel_name, channel_name) != 0) {
347 printf("error: channel name differs\n");
348 ret = 1;
349 goto end;
350 }
351
352 if (condition_domain_type != domain_type) {
353 printf("error: domain type differs\n");
354 ret = 1;
355 goto end;
356 }
357
358 if (is_threshold_ratio) {
359 lttng_evaluation_buffer_usage_get_usage_ratio(
360 evaluation, &buffer_usage_ratio);
361 switch (condition_type) {
362 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
363 if (buffer_usage_ratio > threshold_ratio) {
364 printf("error: buffer usage ratio is bigger than set threshold ratio\n");
365 ret = 1;
366 goto end;
367 }
368 break;
369 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
370 if (buffer_usage_ratio < threshold_ratio) {
371 printf("error: buffer usage ratio is lower than set threshold ratio\n");
372 ret = 1;
373 goto end;
374 }
375 break;
376 default:
377 printf("error: Unknown condition type\n");
378 ret = 1;
379 goto end;
380 }
381 } else {
382 lttng_evaluation_buffer_usage_get_usage(
383 evaluation, &buffer_usage_bytes);
384 switch (condition_type) {
385 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
386 if (buffer_usage_bytes > threshold_bytes) {
387 printf("error: buffer usage ratio is bigger than set threshold bytes\n");
388 ret = 1;
389 goto end;
390 }
391 break;
392 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
393 if (buffer_usage_bytes < threshold_bytes) {
394 printf("error: buffer usage ratio is lower than set threshold bytes\n");
395 ret = 1;
396 goto end;
397 }
398 break;
399 default:
400 printf("error: Unknown condition type\n");
401 ret = 1;
402 goto end;
403 }
404 }
405
406 switch (condition_type) {
407 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
408 string_condition_type = string_low;
409 break;
410 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
411 string_condition_type = string_high;
412 break;
413 default:
414 printf("error: Unknown condition type\n");
415 ret = 1;
416 goto end;
417 }
418
419 printf("notification: %s %d\n", string_condition_type, nr_notifications);
420end:
421 return ret;
422}
This page took 0.044713 seconds and 4 git commands to generate.