tests: trigger action firing policy
[lttng-tools.git] / tests / regression / tools / trigger / utils / notification-client.c
CommitLineData
6ba31891
FD
1/*
2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 */
7
8#include <getopt.h>
9#include <stdbool.h>
10#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/time.h>
15#include <time.h>
16
e393070a 17#include <lttng/condition/on-event.h>
6ba31891
FD
18#include <lttng/lttng.h>
19
20#include "utils.h"
21
22static struct option long_options[] =
23{
24 /* These options set a flag. */
7d59def2 25 {"trigger", required_argument, 0, 't'},
6ba31891 26 {"sync-after-notif-register", required_argument, 0, 'a'},
6ffce1f5
JR
27 /* Default alue for count is 1 */
28 {"count", required_argument, 0, 'b'},
29 /*
30 * When end-trigger is present the reception loop is exited only when a
31 * notification matching the end trigger is received.
32 * Otherwise the loop is exited when the count of notification received
33 * for `trigger` math the `count` argument.
34 */
35 {"end-trigger", required_argument, 0, 'c'},
6ba31891
FD
36 {0, 0, 0, 0}
37};
38
39static bool action_group_contains_notify(
40 const struct lttng_action *action_group)
41{
42 unsigned int i, count;
43 enum lttng_action_status status =
44 lttng_action_group_get_count(action_group, &count);
45
46 if (status != LTTNG_ACTION_STATUS_OK) {
47 printf("Failed to get action count from action group\n");
48 exit(1);
49 }
50
51 for (i = 0; i < count; i++) {
52 const struct lttng_action *action =
53 lttng_action_group_get_at_index(
54 action_group, i);
55 const enum lttng_action_type action_type =
56 lttng_action_get_type(action);
57
58 if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
59 return true;
60 }
61 }
62 return false;
63}
64
7d59def2 65static bool is_trigger_name(const char *expected_trigger_name,
6ba31891
FD
66 struct lttng_notification *notification)
67{
65f64978
JG
68 const char *trigger_name = NULL;
69 enum lttng_trigger_status trigger_status;
70 const struct lttng_trigger *trigger;
71 bool names_match;
6ba31891 72
65f64978
JG
73 trigger = lttng_notification_get_trigger(notification);
74 if (!trigger) {
75 fprintf(stderr, "Failed to get trigger from notification\n");
76 names_match = false;
77 goto end;
6ba31891 78 }
65f64978
JG
79
80 trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
81 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
82 fprintf(stderr, "Failed to get name from notification's trigger\n");
83 names_match = false;
84 goto end;
6ba31891
FD
85 }
86
65f64978 87 names_match = strcmp(expected_trigger_name, trigger_name) == 0;
7d59def2
JR
88 if (!names_match) {
89 fprintf(stderr, "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
90 trigger_name, expected_trigger_name);
91 }
65f64978
JG
92end:
93 return names_match;
6ba31891
FD
94}
95
96int main(int argc, char **argv)
97{
98 int ret;
99 int option;
100 int option_index;
101 const char *expected_trigger_name = NULL;
6ffce1f5 102 const char *end_trigger_name = NULL;
6ba31891
FD
103 struct lttng_triggers *triggers = NULL;
104 unsigned int count, i, subcription_count = 0;
105 enum lttng_trigger_status trigger_status;
106 char *after_notif_register_file_path = NULL;
107 struct lttng_notification_channel *notification_channel = NULL;
6ffce1f5 108 int expected_notifications = 1, notification_count = 0;
6ba31891 109
6ffce1f5
JR
110 while ((option = getopt_long(argc, argv, "a:b:c:t:", long_options,
111 &option_index)) != -1) {
6ba31891
FD
112 switch (option) {
113 case 'a':
114 after_notif_register_file_path = strdup(optarg);
115 break;
6ffce1f5
JR
116 case 'b':
117 expected_notifications = atoi(optarg);
118 break;
119 case 'c':
120 end_trigger_name = strdup(optarg);
121 break;
6ba31891
FD
122 case 't':
123 expected_trigger_name = strdup(optarg);
124 break;
125 case '?':
126 /* getopt_long already printed an error message. */
127 default:
128 ret = -1;
129 goto end;
130 }
131 }
132
133 if (optind != argc) {
134 ret = -1;
135 goto end;
136 }
137
138
139 notification_channel = lttng_notification_channel_create(
140 lttng_session_daemon_notification_endpoint);
141 if (!notification_channel) {
142 fprintf(stderr, "Failed to create notification channel\n");
143 ret = -1;
144 goto end;
145 }
146
147 ret = lttng_list_triggers(&triggers);
148 if (ret != LTTNG_OK) {
149 fprintf(stderr, "Failed to list triggers\n");
7d59def2 150 ret = -1;
6ba31891
FD
151 goto end;
152 }
153
154 trigger_status = lttng_triggers_get_count(triggers, &count);
155 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
156 fprintf(stderr, "Failed to get trigger count\n");
157 ret = -1;
158 goto end;
159 }
160
7d59def2 161 /* Look for the trigger we want to subscribe to. */
6ba31891
FD
162 for (i = 0; i < count; i++) {
163 const struct lttng_trigger *trigger =
164 lttng_triggers_get_at_index(triggers, i);
165 const struct lttng_condition *condition =
166 lttng_trigger_get_const_condition(trigger);
167 const struct lttng_action *action =
168 lttng_trigger_get_const_action(trigger);
169 const enum lttng_action_type action_type =
170 lttng_action_get_type(action);
171 enum lttng_notification_channel_status channel_status;
172 const char *trigger_name = NULL;
173
174 lttng_trigger_get_name(trigger, &trigger_name);
175 if (strcmp(trigger_name, expected_trigger_name)) {
6ffce1f5
JR
176 /* Might match the end event trigger */
177 if (end_trigger_name != NULL &&
178 strcmp(trigger_name,
179 end_trigger_name)) {
180 continue;
181 }
6ba31891 182 }
6ba31891
FD
183 if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
184 action_group_contains_notify(action)) ||
185 action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
186 /* "The action of trigger is not notify, skipping. */
187 continue;
188 }
189
190 channel_status = lttng_notification_channel_subscribe(
191 notification_channel, condition);
192 if (channel_status) {
193 fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
194 trigger_name);
195 ret = -1;
196 goto end;
197 }
198
199 subcription_count++;
200 }
201
202 if (subcription_count == 0) {
6ffce1f5
JR
203 fprintf(stderr, "No matching trigger with a notify action found.\n");
204 ret = -1;
6ba31891
FD
205 goto end;
206 }
207
6ffce1f5
JR
208 if (end_trigger_name != NULL && subcription_count != 2) {
209 fprintf(stderr, "No matching end event trigger with a notify action found.\n");
210 ret = -1;
211 goto end;
212 }
6ba31891
FD
213
214 /*
215 * We registered to the notification of our target trigger. We can now
216 * create the sync file to signify that we are ready.
217 */
218 ret = create_file(after_notif_register_file_path);
219 if (ret != 0) {
220 goto end;
221 }
222
223 for (;;) {
224 struct lttng_notification *notification;
225 enum lttng_notification_channel_status channel_status;
226
227 channel_status =
228 lttng_notification_channel_get_next_notification(
229 notification_channel,
230 &notification);
231 switch (channel_status) {
232 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
233 printf("Dropped notification\n");
7d59def2
JR
234 ret = -1;
235 goto end;
6ba31891 236 case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
7d59def2 237 ret = -1;
6ba31891
FD
238 goto end;
239 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
240 break;
241 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
242 printf("Notification channel was closed by peer.\n");
7d59def2 243 ret = -1;
6ba31891
FD
244 break;
245 default:
246 fprintf(stderr, "A communication error occurred on the notification channel.\n");
247 ret = -1;
248 goto end;
249 }
250
6ffce1f5
JR
251 /* Early exit check. */
252 if (end_trigger_name != NULL &&
253 is_trigger_name(end_trigger_name,
254 notification)) {
255 /* Exit the loop immediately. */
256 printf("Received end event notification from trigger %s\n",
257 end_trigger_name);
258 lttng_notification_destroy(notification);
259 goto evaluate_success;
260 }
261
7d59def2 262 ret = is_trigger_name(expected_trigger_name, notification);
6ba31891 263 lttng_notification_destroy(notification);
7d59def2
JR
264 if (!ret) {
265 ret = -1;
266 goto end;
6ffce1f5
JR
267 }
268
269 printf("Received event notification from trigger %s\n",
270 expected_trigger_name);
271 notification_count++;
272 if (end_trigger_name == NULL &&
273 expected_notifications == notification_count) {
274 /*
275 * Here the loop exit is controlled by the number of
276 * notification and not by the reception of the end
277 * event trigger notification. This represent the
278 * default behavior.
279 *
280 */
281 goto evaluate_success;
6ba31891
FD
282 }
283 }
6ffce1f5
JR
284
285evaluate_success:
286 if (expected_notifications == notification_count) {
287 /* Success */
288 ret = 0;
289 } else {
290 fprintf(stderr, "Expected %d notification got %d\n",
291 expected_notifications, notification_count);
292 ret = 1;
293 }
294
6ba31891
FD
295end:
296 lttng_triggers_destroy(triggers);
297 lttng_notification_channel_destroy(notification_channel);
298 return !!ret;
299}
This page took 0.03541 seconds and 4 git commands to generate.