lttng-ctl: separate support of named/unnamed trigger registration
[lttng-tools.git] / tests / regression / tools / notification / rotation.c
1 /*
2 * rotation.c
3 *
4 * Tests suite for LTTng notification API (rotation notifications)
5 *
6 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * SPDX-License-Identifier: MIT
9 *
10 */
11
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <assert.h>
15 #include <tap/tap.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <lttng/lttng.h>
19
20 #define TEST_COUNT 36
21
22 struct session {
23 const char *name;
24 const char *output_path;
25 };
26
27 uint64_t expected_rotation_id = UINT64_MAX;
28
29 static
30 int test_condition(struct lttng_condition *condition, const char *type_name)
31 {
32 int ret = 0;
33 const char *out_session_name;
34 const char * const session_name = "test session name";
35 enum lttng_condition_status status;
36
37 status = lttng_condition_session_rotation_get_session_name(condition,
38 &out_session_name);
39 ok(status == LTTNG_CONDITION_STATUS_UNSET,
40 "Getting unset name of %s condition fails with LTTNG_CONDITION_STATUS_UNSET",
41 type_name);
42
43 status = lttng_condition_session_rotation_set_session_name(condition,
44 session_name);
45 ok(status == LTTNG_CONDITION_STATUS_OK,
46 "Setting session name \"%s\" of %s condition succeeds",
47 session_name, type_name);
48
49 status = lttng_condition_session_rotation_get_session_name(condition,
50 &out_session_name);
51 ok(status == LTTNG_CONDITION_STATUS_OK,
52 "Getting name of %s condition succeeds",
53 type_name);
54
55 ok(out_session_name && !strcmp(session_name, out_session_name),
56 "Session name returned by %s condition matches the expected name",
57 type_name);
58 return ret;
59 }
60
61 static
62 int setup_rotation_trigger(const struct session *session,
63 struct lttng_notification_channel *notification_channel)
64 {
65 int ret;
66 struct lttng_condition *rotation_ongoing_condition = NULL;
67 struct lttng_condition *rotation_completed_condition = NULL;
68 struct lttng_action *notify = NULL;
69 struct lttng_trigger *rotation_ongoing_trigger = NULL;
70 struct lttng_trigger *rotation_completed_trigger = NULL;
71 enum lttng_condition_status condition_status;
72 enum lttng_notification_channel_status notification_channel_status;
73 enum lttng_error_code ret_code;
74
75 notify = lttng_action_notify_create();
76 if (!notify) {
77 ret = -1;
78 goto end;
79 }
80
81 /* Create rotation ongoing and completed conditions. */
82 rotation_ongoing_condition =
83 lttng_condition_session_rotation_ongoing_create();
84 ok(rotation_ongoing_condition, "Create session rotation ongoing condition");
85 if (!rotation_ongoing_condition) {
86 ret = -1;
87 goto end;
88 }
89 ret = test_condition(rotation_ongoing_condition, "rotation ongoing");
90 if (ret) {
91 goto end;
92 }
93 condition_status = lttng_condition_session_rotation_set_session_name(
94 rotation_ongoing_condition, session->name);
95 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
96 ret = -1;
97 diag("Failed to set session name on session rotation ongoing condition");
98 goto end;
99 }
100
101 rotation_completed_condition =
102 lttng_condition_session_rotation_completed_create();
103 ok(rotation_completed_condition, "Create session rotation completed condition");
104 if (!rotation_completed_condition) {
105 ret = -1;
106 goto end;
107 }
108 ret = test_condition(rotation_completed_condition, "rotation completed");
109 if (ret) {
110 diag("Failed to set session name on session rotation completed condition");
111 goto end;
112 }
113 condition_status = lttng_condition_session_rotation_set_session_name(
114 rotation_completed_condition, session->name);
115 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
116 ret = -1;
117 goto end;
118 }
119
120 notification_channel_status = lttng_notification_channel_subscribe(
121 notification_channel, rotation_ongoing_condition);
122 ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
123 "Subscribe to session rotation ongoing notifications");
124 if (notification_channel_status !=
125 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
126 ret = -1;
127 goto end;
128 }
129 notification_channel_status = lttng_notification_channel_subscribe(
130 notification_channel, rotation_completed_condition);
131 ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
132 "Subscribe to session rotation completed notifications");
133 if (notification_channel_status !=
134 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
135 ret = -1;
136 goto end;
137 }
138
139 /* Create rotation ongoing and completed triggers. */
140 rotation_ongoing_trigger = lttng_trigger_create(
141 rotation_ongoing_condition, notify);
142 ok(rotation_ongoing_trigger, "Create a rotation ongoing notification trigger");
143 if (!rotation_ongoing_trigger) {
144 ret = -1;
145 goto end;
146 }
147
148 rotation_completed_trigger = lttng_trigger_create(
149 rotation_completed_condition, notify);
150 ok(rotation_completed_trigger, "Create a rotation completed notification trigger");
151 if (!rotation_completed_trigger) {
152 ret = -1;
153 goto end;
154 }
155
156 /* Register rotation ongoing and completed triggers. */
157 ret_code = lttng_register_trigger_with_automatic_name(
158 rotation_ongoing_trigger);
159 ok(ret_code == LTTNG_OK, "Registered session rotation ongoing trigger");
160 if (ret_code != LTTNG_OK) {
161 ret = -ret_code;
162 goto end;
163 }
164
165 ret_code = lttng_register_trigger_with_automatic_name(
166 rotation_completed_trigger);
167 ok(ret_code == LTTNG_OK,
168 "Registered session rotation completed trigger");
169 if (ret_code != LTTNG_OK) {
170 ret = -ret_code;
171 goto end;
172 }
173
174 end:
175 lttng_trigger_destroy(rotation_ongoing_trigger);
176 lttng_trigger_destroy(rotation_completed_trigger);
177 lttng_condition_destroy(rotation_ongoing_condition);
178 lttng_condition_destroy(rotation_completed_condition);
179 lttng_action_destroy(notify);
180 return ret;
181 }
182
183 static
184 int test_notification(
185 struct lttng_notification_channel *notification_channel,
186 const struct session *session,
187 const char *expected_notification_type_name,
188 enum lttng_condition_type expected_condition_type)
189 {
190 int ret = 0;
191 bool notification_pending;
192 enum lttng_notification_channel_status notification_channel_status;
193 enum lttng_condition_status condition_status;
194 enum lttng_evaluation_status evaluation_status;
195 enum lttng_trace_archive_location_status location_status;
196 enum lttng_condition_type condition_type;
197 struct lttng_notification *notification = NULL;
198 const struct lttng_condition *condition;
199 const struct lttng_evaluation *evaluation;
200 const char *session_name = NULL;
201 const struct lttng_trace_archive_location *location = NULL;
202 uint64_t rotation_id = UINT64_MAX;
203 const char *chunk_path = NULL;
204
205 notification_channel_status = lttng_notification_channel_has_pending_notification(
206 notification_channel, &notification_pending);
207 ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
208 "Check for %s notification pending on notification channel",
209 expected_notification_type_name);
210 if (notification_channel_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
211 ret = -1;
212 goto end;
213 }
214
215 ok(notification_pending,
216 "Session %s notification is pending on notification channel",
217 expected_notification_type_name);
218 if (!notification_pending) {
219 ret = -1;
220 goto end;
221 }
222
223 notification_channel_status = lttng_notification_channel_get_next_notification(
224 notification_channel, &notification);
225 ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification,
226 "Get %s notification from notification channel",
227 expected_notification_type_name);
228 if (notification_channel_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK || !notification) {
229 ret = -1;
230 goto end;
231 }
232
233 condition = lttng_notification_get_condition(notification);
234 if (!condition) {
235 diag("Failed to get notification condition");
236 ret = -1;
237 goto end;
238 }
239
240 condition_type = lttng_condition_get_type(condition);
241 ok(condition_type == expected_condition_type,
242 "Notification condition obtained from notification channel is of type \"%s\"",
243 expected_notification_type_name);
244 if (condition_type != expected_condition_type) {
245 ret = -1;
246 goto end;
247 }
248
249 condition_status = lttng_condition_session_rotation_get_session_name(
250 condition, &session_name);
251 ok(condition_status == LTTNG_CONDITION_STATUS_OK && session_name &&
252 !strcmp(session_name, session->name),
253 "Condition obtained from notification has the correct session name assigned");
254 if (condition_status != LTTNG_CONDITION_STATUS_OK || !session_name) {
255 ret = -1;
256 goto end;
257 }
258
259 evaluation = lttng_notification_get_evaluation(notification);
260 if (!evaluation) {
261 diag("Failed to get notification evaluation");
262 ret = -1;
263 goto end;
264 }
265 condition_type = lttng_evaluation_get_type(evaluation);
266 ok(condition_type == expected_condition_type,
267 "Condition evaluation obtained from notification channel is of type \"%s\"",
268 expected_notification_type_name);
269 if (condition_type != expected_condition_type) {
270 ret = -1;
271 goto end;
272 }
273
274 evaluation_status = lttng_evaluation_session_rotation_get_id(evaluation,
275 &rotation_id);
276 ok(evaluation_status == LTTNG_EVALUATION_STATUS_OK,
277 "Get %s id from notification evaluation",
278 expected_notification_type_name);
279 if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
280 ret = -1;
281 goto end;
282 }
283
284 if (expected_condition_type != LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED) {
285 /*
286 * Remaining tests only apply to "session rotation completed"
287 * notifications.
288 */
289 goto end;
290 }
291
292 evaluation_status = lttng_evaluation_session_rotation_completed_get_location(
293 evaluation, &location);
294 ok(evaluation_status == LTTNG_EVALUATION_STATUS_OK && location,
295 "Get session %s chunk location from evaluation",
296 expected_notification_type_name);
297 if (evaluation_status != LTTNG_EVALUATION_STATUS_OK || !location) {
298 ret = -1;
299 goto end;
300 }
301
302 ok(lttng_trace_archive_location_get_type(location) == LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL,
303 "Location returned from the session rotation completed notification is of type 'local'");
304
305 location_status = lttng_trace_archive_location_local_get_absolute_path(
306 location, &chunk_path);
307 ok(location_status == LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK && chunk_path,
308 "Retrieved path from location returned by the session rotation completed notification");
309 diag("Chunk available at %s", chunk_path ? chunk_path : "NULL");
310
311 ok(chunk_path && !strncmp(session->output_path, chunk_path, strlen(session->output_path)),
312 "Returned path from location starts with the output path");
313
314 end:
315 lttng_notification_destroy(notification);
316 return ret;
317 }
318
319 static
320 int test_rotation_ongoing_notification(
321 struct lttng_notification_channel *notification_channel,
322 struct session *session)
323 {
324 return test_notification(notification_channel, session,
325 "rotation ongoing",
326 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING);
327 }
328
329 static
330 int test_rotation_completed_notification(
331 struct lttng_notification_channel *notification_channel,
332 struct session *session)
333 {
334 return test_notification(notification_channel, session,
335 "rotation completed",
336 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED);
337 }
338
339 int main(int argc, const char *argv[])
340 {
341 int ret = 0;
342 struct session session = { 0 };
343 struct lttng_notification_channel *notification_channel = NULL;
344 struct lttng_rotation_handle *rotation_handle = NULL;
345 enum lttng_rotation_status rotation_status;
346 enum lttng_rotation_state rotation_state =
347 LTTNG_ROTATION_STATE_NO_ROTATION;
348
349 if (argc != 3) {
350 puts("Usage: rotation SESSION_NAME SESSION_OUTPUT_PATH");
351 ret = 1;
352 goto error;
353 }
354
355 session.name = argv[1];
356 session.output_path = argv[2];
357
358 plan_tests(TEST_COUNT);
359
360 notification_channel = lttng_notification_channel_create(
361 lttng_session_daemon_notification_endpoint);
362 if (!notification_channel) {
363 diag("Failed to create notification channel");
364 ret = -1;
365 goto error;
366 }
367
368 ret = setup_rotation_trigger(&session, notification_channel);
369 if (ret) {
370 goto error;
371 }
372
373 /* Start rotation and wait for its completion. */
374 ret = lttng_rotate_session(session.name, NULL, &rotation_handle);
375 ok(ret >= 0 && rotation_handle, "Start rotation of session \"%s\"",
376 session.name);
377 if (ret < 0 || !rotation_handle) {
378 goto error;
379 }
380
381 do {
382 rotation_status = lttng_rotation_handle_get_state(
383 rotation_handle, &rotation_state);
384 } while (rotation_state == LTTNG_ROTATION_STATE_ONGOING &&
385 rotation_status == LTTNG_ROTATION_STATUS_OK);
386 ok(rotation_status == LTTNG_ROTATION_STATUS_OK &&
387 rotation_state == LTTNG_ROTATION_STATE_COMPLETED,
388 "Complete rotation of session \"%s\"", session.name);
389
390 /*
391 * After a rotation has completed, we can expect two notifications to
392 * be queued:
393 * - Session rotation ongoing
394 * - Session rotation completed
395 */
396 ret = test_rotation_ongoing_notification(notification_channel,
397 &session);
398 if (ret) {
399 goto error;
400 }
401
402 ret = test_rotation_completed_notification(notification_channel,
403 &session);
404 if (ret) {
405 goto error;
406 }
407 error:
408 lttng_notification_channel_destroy(notification_channel);
409 lttng_rotation_handle_destroy(rotation_handle);
410 return exit_status();
411 }
This page took 0.038127 seconds and 5 git commands to generate.