X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=tests%2Fregression%2Ftools%2Fnotification%2Frotation.c;fp=tests%2Fregression%2Ftools%2Fnotification%2Frotation.c;h=ed9ae8944c29c90e2fe938291367c6af610b18a8;hb=88a5c0a9ce2333f12a1bd5d6b0ea527b86cde819;hp=0000000000000000000000000000000000000000;hpb=bbcab087101aeaf9811074f9e622290e503104ca;p=lttng-tools.git 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; +}