Tests: add a session rotation ongoing/completed notification test
[lttng-tools.git] / tests / regression / tools / notification / rotation.c
diff --git a/tests/regression/tools/notification/rotation.c b/tests/regression/tools/notification/rotation.c
new file mode 100644 (file)
index 0000000..ed9ae89
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * rotation.c
+ *
+ * Tests suite for LTTng notification API (rotation notifications)
+ *
+ * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <tap/tap.h>
+#include <stdint.h>
+#include <lttng/rotation.h>
+#include <lttng/notification/channel.h>
+#include <lttng/notification/notification.h>
+#include <lttng/condition/evaluation.h>
+#include <lttng/condition/condition.h>
+#include <lttng/endpoint.h>
+#include <lttng/action/notify.h>
+#include <lttng/action/action.h>
+#include <lttng/trigger/trigger.h>
+#include <lttng/condition/session-rotation.h>
+#include <string.h>
+
+#define TEST_COUNT 36
+
+struct session {
+       const char *name;
+       const char *output_path;
+};
+
+uint64_t expected_rotation_id = UINT64_MAX;
+
+static
+int test_condition(struct lttng_condition *condition, const char *type_name)
+{
+       int ret = 0;
+       const char *out_session_name;
+       const char * const session_name = "test session name";
+       enum lttng_condition_status status;
+
+       status = lttng_condition_session_rotation_get_session_name(condition,
+                       &out_session_name);
+       ok(status == LTTNG_CONDITION_STATUS_UNSET,
+                       "Getting unset name of %s condition fails with LTTNG_CONDITION_STATUS_UNSET",
+                       type_name);
+
+       status = lttng_condition_session_rotation_set_session_name(condition,
+                       session_name);
+       ok(status == LTTNG_CONDITION_STATUS_OK,
+                       "Setting session name \"%s\" of %s condition succeeds",
+                       session_name, type_name);
+
+       status = lttng_condition_session_rotation_get_session_name(condition,
+                       &out_session_name);
+       ok(status == LTTNG_CONDITION_STATUS_OK,
+                       "Getting name of %s condition succeeds",
+                       type_name);
+
+       ok(out_session_name && !strcmp(session_name, out_session_name),
+                       "Session name returned by %s condition matches the expected name",
+                       type_name);
+end:
+       return ret;
+}
+
+static
+int setup_rotation_trigger(const struct session *session,
+               struct lttng_notification_channel *notification_channel)
+{
+       int ret;
+       struct lttng_condition *rotation_ongoing_condition = NULL;
+       struct lttng_condition *rotation_completed_condition = NULL;
+       struct lttng_action *notify = NULL;
+       struct lttng_trigger *rotation_ongoing_trigger = NULL;
+       struct lttng_trigger *rotation_completed_trigger = NULL;
+       enum lttng_condition_status condition_status;
+       enum lttng_notification_channel_status notification_channel_status;
+
+       notify = lttng_action_notify_create();
+       if (!notify) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Create rotation ongoing and completed conditions. */
+       rotation_ongoing_condition =
+                       lttng_condition_session_rotation_ongoing_create();
+       ok(rotation_ongoing_condition, "Create session rotation ongoing condition");
+       if (!rotation_ongoing_condition) {
+               ret = -1;
+               goto end;
+       }
+       ret = test_condition(rotation_ongoing_condition, "rotation ongoing");
+       if (ret) {
+               goto end;
+       }
+       condition_status = lttng_condition_session_rotation_set_session_name(
+                       rotation_ongoing_condition, session->name);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               ret = -1;
+               diag("Failed to set session name on session rotation ongoing condition");
+               goto end;
+       }
+
+       rotation_completed_condition =
+                       lttng_condition_session_rotation_completed_create();
+       ok(rotation_completed_condition, "Create session rotation completed condition");
+       if (!rotation_completed_condition) {
+               ret = -1;
+               goto end;
+       }
+       ret = test_condition(rotation_completed_condition, "rotation completed");
+       if (ret) {
+               diag("Failed to set session name on session rotation completed condition");
+               goto end;
+       }
+       condition_status = lttng_condition_session_rotation_set_session_name(
+                       rotation_completed_condition, session->name);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       notification_channel_status = lttng_notification_channel_subscribe(
+                       notification_channel, rotation_ongoing_condition);
+       ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to session rotation ongoing notifications");
+       if (notification_channel_status !=
+                       LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+       notification_channel_status = lttng_notification_channel_subscribe(
+                       notification_channel, rotation_completed_condition);
+       ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to session rotation completed notifications");
+       if (notification_channel_status !=
+                       LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Create rotation ongoing and completed triggers. */
+       rotation_ongoing_trigger = lttng_trigger_create(
+                       rotation_ongoing_condition, notify);
+       ok(rotation_ongoing_trigger, "Create a rotation ongoing notification trigger");
+       if (!rotation_ongoing_trigger) {
+               ret = -1;
+               goto end;
+       }
+
+       rotation_completed_trigger = lttng_trigger_create(
+                       rotation_completed_condition, notify);
+       ok(rotation_completed_trigger, "Create a rotation completed notification trigger");
+       if (!rotation_completed_trigger) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Register rotation ongoing and completed triggers. */
+       ret = lttng_register_trigger(rotation_ongoing_trigger);
+       ok(ret == 0, "Registered session rotation ongoing trigger");
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_register_trigger(rotation_completed_trigger);
+       ok(ret == 0, "Registered session rotation completed trigger");
+       if (ret) {
+               goto end;
+       }
+end:
+       lttng_trigger_destroy(rotation_ongoing_trigger);
+       lttng_trigger_destroy(rotation_completed_trigger);
+       lttng_condition_destroy(rotation_ongoing_condition);
+       lttng_condition_destroy(rotation_completed_condition);
+       lttng_action_destroy(notify);
+       return ret;
+}
+
+static
+int test_notification(
+               struct lttng_notification_channel *notification_channel,
+               const struct session *session,
+               const char *expected_notification_type_name,
+               enum lttng_condition_type expected_condition_type)
+{
+       int ret = 0;
+       bool notification_pending;
+       enum lttng_notification_channel_status notification_channel_status;
+       enum lttng_condition_status condition_status;
+       enum lttng_evaluation_status evaluation_status;
+       enum lttng_trace_archive_location_status location_status;
+       enum lttng_condition_type condition_type;
+       struct lttng_notification *notification = NULL;
+       const struct lttng_condition *condition;
+       const struct lttng_evaluation *evaluation;
+       const char *session_name = NULL;
+       const struct lttng_trace_archive_location *location = NULL;
+       uint64_t rotation_id = UINT64_MAX;
+       const char *chunk_path = NULL;
+
+       notification_channel_status = lttng_notification_channel_has_pending_notification(
+                       notification_channel, &notification_pending);
+       ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Check for %s notification pending on notification channel",
+                       expected_notification_type_name);
+       if (notification_channel_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       ok(notification_pending,
+                       "Session %s notification is pending on notification channel",
+                       expected_notification_type_name);
+       if (!notification_pending) {
+               ret = -1;
+               goto end;
+       }
+
+       notification_channel_status = lttng_notification_channel_get_next_notification(
+                       notification_channel, &notification);
+       ok(notification_channel_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification,
+                       "Get %s notification from notification channel",
+                       expected_notification_type_name);
+       if (notification_channel_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK || !notification) {
+               ret = -1;
+               goto end;
+       }
+
+       condition = lttng_notification_get_condition(notification);
+       if (!condition) {
+               diag("Failed to get notification condition");
+               ret = -1;
+               goto end;
+       }
+
+       condition_type = lttng_condition_get_type(condition);
+       ok(condition_type == expected_condition_type,
+                       "Notification condition obtained from notification channel is of type \"%s\"",
+                       expected_notification_type_name);
+       if (condition_type != expected_condition_type) {
+               ret = -1;
+               goto end;
+       }
+
+       condition_status = lttng_condition_session_rotation_get_session_name(
+                       condition, &session_name);
+       ok(condition_status == LTTNG_CONDITION_STATUS_OK && session_name &&
+                       !strcmp(session_name, session->name),
+                       "Condition obtained from notification has the correct session name assigned");
+       if (condition_status != LTTNG_CONDITION_STATUS_OK || !session_name) {
+               ret = -1;
+               goto end;
+       }
+
+       evaluation = lttng_notification_get_evaluation(notification);
+       if (!evaluation) {
+               diag("Failed to get notification evaluation");
+               ret = -1;
+               goto end;
+       }
+       condition_type = lttng_evaluation_get_type(evaluation);
+       ok(condition_type == expected_condition_type,
+                       "Condition evaluation obtained from notification channel is of type \"%s\"",
+                       expected_notification_type_name);
+       if (condition_type != expected_condition_type) {
+               ret = -1;
+               goto end;
+       }
+
+       evaluation_status = lttng_evaluation_session_rotation_get_id(evaluation,
+                       &rotation_id);
+       ok(evaluation_status == LTTNG_EVALUATION_STATUS_OK,
+                       "Get %s id from notification evaluation",
+                       expected_notification_type_name);
+       if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       if (expected_condition_type != LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED) {
+               /*
+                * Remaining tests only apply to "session rotation completed"
+                * notifications.
+                */
+               goto end;
+       }
+
+       evaluation_status = lttng_evaluation_session_rotation_completed_get_location(
+                       evaluation, &location);
+       ok(evaluation_status == LTTNG_EVALUATION_STATUS_OK && location,
+                       "Get session %s chunk location from evaluation",
+                       expected_notification_type_name);
+       if (evaluation_status != LTTNG_EVALUATION_STATUS_OK || !location) {
+               ret = -1;
+               goto end;
+       }
+
+       ok(lttng_trace_archive_location_get_type(location) == LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL,
+                       "Location returned from the session rotation completed notification is of type 'local'");
+
+       location_status = lttng_trace_archive_location_local_get_absolute_path(
+                       location, &chunk_path);
+       ok(location_status == LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK,
+                       "Retrieved path from location returned by the session rotation completed notification");
+       diag("Chunk available at %s", chunk_path ? chunk_path : "NULL");
+       ok(!strncmp(session->output_path, chunk_path, strlen(session->output_path)),
+                       "Returned path from location starts with the output path");
+
+end:
+       lttng_notification_destroy(notification);
+       return ret;
+}
+
+static
+int test_rotation_ongoing_notification(
+               struct lttng_notification_channel *notification_channel,
+               struct session *session)
+{
+       return test_notification(notification_channel, session,
+                       "rotation ongoing",
+                       LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING);
+}
+
+static
+int test_rotation_completed_notification(
+               struct lttng_notification_channel *notification_channel,
+               struct session *session)
+{
+       return test_notification(notification_channel, session,
+                       "rotation completed",
+                       LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED);
+}
+
+int main(int argc, const char *argv[])
+{
+       int ret = 0;
+       struct session session = { 0 };
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_rotation_handle *rotation_handle = NULL;
+       enum lttng_rotation_status rotation_status;
+       enum lttng_rotation_state rotation_state =
+                       LTTNG_ROTATION_STATE_NO_ROTATION;
+
+       if (argc != 3) {
+               puts("Usage: rotation SESSION_NAME SESSION_OUTPUT_PATH");
+               ret = 1;
+               goto error;
+       }
+
+       session.name = argv[1];
+       session.output_path = argv[2];
+
+       plan_tests(TEST_COUNT);
+       if (ret) {
+               goto error;
+       }
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       if (!notification_channel) {
+               diag("Failed to create notification channel");
+               ret = -1;
+               goto error;
+       }
+
+       ret = setup_rotation_trigger(&session, notification_channel);
+       if (ret) {
+               goto error;
+       }
+
+       /* Start rotation and wait for its completion. */
+       ret = lttng_rotate_session(session.name, NULL, &rotation_handle);
+       ok(ret >= 0 && rotation_handle, "Start rotation of session \"%s\"",
+                       session.name);
+       if (ret < 0 || !rotation_handle) {
+               goto error;
+       }
+
+       do {
+               rotation_status = lttng_rotation_handle_get_state(
+                               rotation_handle, &rotation_state);
+       } while (rotation_state == LTTNG_ROTATION_STATE_ONGOING &&
+                       rotation_status == LTTNG_ROTATION_STATUS_OK);
+       ok(rotation_status == LTTNG_ROTATION_STATUS_OK &&
+                       rotation_state == LTTNG_ROTATION_STATE_COMPLETED,
+                       "Complete rotation of session \"%s\"", session.name);
+
+       /*
+        * After a rotation has completed, we can expect two notifications to
+        * be queued:
+        *  - Session rotation ongoing
+        *  - Session rotation completed
+        */
+       ret = test_rotation_ongoing_notification(notification_channel,
+                       &session);
+       if (ret) {
+               goto error;
+       }
+
+       ret = test_rotation_completed_notification(notification_channel,
+                       &session);
+       if (ret) {
+               goto error;
+       }
+error:
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_rotation_handle_destroy(rotation_handle);
+       return ret;
+}
This page took 0.028976 seconds and 5 git commands to generate.