Tests: add a session rotation ongoing/completed notification test
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 17 Aug 2018 17:26:07 +0000 (13:26 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 24 Aug 2018 01:42:22 +0000 (21:42 -0400)
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
.gitignore
tests/regression/tools/notification/Makefile.am
tests/regression/tools/notification/rotation.c [new file with mode: 0644]
tests/regression/tools/notification/test_rotation [new file with mode: 0755]

index 57de6e01daffad578b4baf5549e45cd3be320177..224f6d4f4d120d9a09582fe3ed5e084127dd6297 100644 (file)
@@ -92,6 +92,7 @@ health_check
 /tests/regression/tools/notification/base_client
 /tests/regression/tools/notification/notification
 /tests/regression/tools/rotation/schedule_api
+/tests/regression/tools/notification/rotation
 /tests/regression/ust/overlap/demo/demo
 /tests/regression/ust/linking/demo_builtin
 /tests/regression/ust/linking/demo_static
index 41adc69330c8329eee990a5832141ff3067d03da..33e95886d44bd78708f2ffa02694f375e5197dbc 100644 (file)
@@ -5,7 +5,7 @@ AM_LDFLAGS =
 LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 LIB_LTTNG_CTL = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
-noinst_PROGRAMS = base_client notification
+noinst_PROGRAMS = base_client notification rotation
 
 if NO_SHARED
 
@@ -30,8 +30,11 @@ base_client_LDADD = $(LIB_LTTNG_CTL)
 notification_SOURCES = notification.c
 notification_LDADD = $(LIB_LTTNG_CTL) $(LIBTAP) -lm
 
-noinst_SCRIPTS = test_notification_ust test_notification_ust test_notification_multi_app
-EXTRA_DIST = test_notification_ust test_notification_kernel test_notification_multi_app
+rotation_SOURCES = rotation.c
+rotation_LDADD = $(LIB_LTTNG_CTL) $(LIBTAP) -lm
+
+noinst_SCRIPTS = test_notification_ust test_notification_ust test_notification_multi_app test_rotation
+EXTRA_DIST = test_notification_ust test_notification_kernel test_notification_multi_app test_rotation
 
 
 all-local:
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;
+}
diff --git a/tests/regression/tools/notification/test_rotation b/tests/regression/tools/notification/test_rotation
new file mode 100755 (executable)
index 0000000..250f1b3
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# Copyright (C) - 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; version 2.1 of the License.
+#
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+
+CURDIR=$(dirname $0)/
+TESTDIR=$CURDIR/../../../
+
+TESTAPP_PATH="$TESTDIR/utils/testapp"
+TESTAPP_NAME="gen-ust-events"
+TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
+
+SESSION_NAME="my_session"
+TMP_DIR=$(mktemp -d)
+SESSION_OUTPUT_PATH=$TMP_DIR/output
+EVENT_NAME="tp:tptest"
+
+PAGE_SIZE=$(getconf PAGE_SIZE)
+SUBBUF_SIZE=$(expr $PAGE_SIZE \* 8)
+
+FILE_SYNC_AFTER_FIRST_EVENT=$(mktemp -u)
+
+NR_ITER=-1
+NR_USEC_WAIT=5
+
+DIR=$(readlink -f $TESTDIR)
+
+source $TESTDIR/utils/utils.sh
+start_lttng_sessiond_notap
+
+create_lttng_session_notap $SESSION_NAME $SESSION_OUTPUT_PATH
+
+enable_ust_lttng_channel_notap $SESSION_NAME $CHANNEL_NAME --subbuf-size=$SUBBUF_SIZE
+enable_ust_lttng_event_notap $SESSION_NAME $EVENT_NAME $CHANNEL_NAME
+
+start_lttng_tracing_notap $SESSION_NAME
+
+$TESTAPP_BIN $NR_ITER $NR_USEC_WAIT $FILE_SYNC_AFTER_FIRST_EVENT &
+APP_PID=$!
+while [ ! -f "${FILE_SYNC_AFTER_FIRST_EVENT}" ]; do
+       sleep 0.5
+done
+
+# The rotation application handles the actual testing once the tracing session
+# has been setup.
+$CURDIR/rotation $SESSION_NAME $SESSION_OUTPUT_PATH
+if [ $? -ne 0 ]; then
+       diag "Failed to run rotation notification client"
+fi
+
+stop_lttng_tracing_notap $SESSION_NAME
+
+stop_lttng_sessiond_notap
+
+# On ungraceful kill the app is cleaned up via the full_cleanup call
+# Suppress kill message
+kill -9 $APP_PID
+wait $APP_PID 2> /dev/null
+
+rm -rf $TMP_DIR
+rm $FILE_SYNC_AFTER_FIRST_EVENT 2> /dev/null
This page took 0.031777 seconds and 4 git commands to generate.