From: Jérémie Galarneau Date: Fri, 17 Aug 2018 17:26:07 +0000 (-0400) Subject: Tests: add a session rotation ongoing/completed notification test X-Git-Tag: v2.11.0-rc1~108 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=88a5c0a9ce2333f12a1bd5d6b0ea527b86cde819;p=lttng-tools.git Tests: add a session rotation ongoing/completed notification test Signed-off-by: Jérémie Galarneau --- diff --git a/.gitignore b/.gitignore index 57de6e01d..224f6d4f4 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/tests/regression/tools/notification/Makefile.am b/tests/regression/tools/notification/Makefile.am index 41adc6933..33e95886d 100644 --- a/tests/regression/tools/notification/Makefile.am +++ b/tests/regression/tools/notification/Makefile.am @@ -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 index 000000000..ed9ae8944 --- /dev/null +++ b/tests/regression/tools/notification/rotation.c @@ -0,0 +1,431 @@ +/* + * rotation.c + * + * Tests suite for LTTng notification API (rotation notifications) + * + * Copyright (C) 2017 Jérémie Galarneau + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, ¬ification_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, ¬ification); + 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 index 000000000..250f1b3f6 --- /dev/null +++ b/tests/regression/tools/notification/test_rotation @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Copyright (C) - 2017 Jérémie Galarneau +# +# 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