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