tests/regression/tools/relayd-grouping/Makefile
tests/regression/tools/clear/Makefile
tests/regression/tools/trigger/Makefile
+ tests/regression/tools/trigger/start-stop/Makefile
+ tests/regression/tools/trigger/utils/Makefile
tests/regression/ust/Makefile
tests/regression/ust/nprocesses/Makefile
tests/regression/ust/high-throughput/Makefile
tools/clear/test_ust \
tools/clear/test_kernel \
tools/tracker/test_event_tracker \
+ tools/trigger/start-stop/test_start_stop \
tools/trigger/test_add_trigger_cli \
tools/trigger/test_list_triggers_cli \
tools/trigger/test_remove_trigger_cli
+SUBDIRS=utils start-stop
+
noinst_SCRIPTS = test_add_trigger_cli \
test_list_triggers_cli \
test_remove_trigger_cli
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+
+noinst_SCRIPTS = test_start_stop
+
+EXTRA_DIST = test_start_stop
+
+all-local:
+ @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+ for script in $(EXTRA_DIST); do \
+ cp -f $(srcdir)/$$script $(builddir); \
+ done; \
+ fi
+
+clean-local:
+ @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+ for script in $(EXTRA_DIST); do \
+ rm -f $(builddir)/$$script; \
+ done; \
+ fi
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+
+TEST_DESC="Triggers - Start and stop actions"
+
+CURDIR=$(dirname "$0")/
+TESTDIR=${CURDIR}/../../../..
+
+# shellcheck source=../../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+
+TESTAPP_PATH="$TESTDIR/utils/testapp"
+GEN_UST_EVENTS_TESTAPP_NAME="gen-ust-events"
+GEN_UST_EVENTS_TESTAPP_BIN="$TESTAPP_PATH/$GEN_UST_EVENTS_TESTAPP_NAME/$GEN_UST_EVENTS_TESTAPP_NAME"
+FULL_LTTNG_BIN="$TESTDIR/../src/bin/lttng/$LTTNG_BIN"
+NOTIFICATION_CLIENT_BIN="$CURDIR/../utils/notification-client"
+NUM_TESTS=18
+
+NR_ITER=5
+NR_USEC_WAIT=5
+
+function lttng_add_trigger_ust()
+{
+ local expected_to_fail="$1"
+ local trigger_name="$2"
+ shift 2
+
+ "$FULL_LTTNG_BIN" add-trigger --id "$trigger_name" "$@" 1> /dev/null 2> /dev/null
+ ret=$?
+ if [[ $expected_to_fail -eq "1" ]]; then
+ test "$ret" -ne "0"
+ ok $? "Add trigger $trigger_name failed as expected"
+ else
+ ok $ret "Add trigger $trigger_name"
+ fi
+}
+
+function lttng_remove_trigger_ust()
+{
+ local expected_to_fail="$1"
+ local trigger_name="$2"
+
+ "$FULL_LTTNG_BIN" remove-trigger "$trigger_name" 1> /dev/null 2> /dev/null
+ ret=$?
+ if [[ $expected_to_fail -eq "1" ]]; then
+ test "$ret" -ne "0"
+ ok $? "Remove trigger $trigger_name failed as expected"
+ else
+ ok $ret "Remove trigger $trigger_name"
+ fi
+}
+
+function lttng_add_trigger_ust_ok()
+{
+ lttng_add_trigger_ust 0 "$@"
+}
+
+function lttng_remove_trigger_ust_ok()
+{
+ lttng_remove_trigger_ust 0 "$@"
+}
+
+function lttng_session_is_active()
+{
+ local SESSION_NAME="$1"
+ "$FULL_LTTNG_BIN" list "$SESSION_NAME" | grep "Tracing session" | grep -q "\[active\]"
+
+ ok $ret "Session \"$SESSION_NAME\" is active"
+}
+
+function lttng_session_is_inactive()
+{
+ local SESSION_NAME="$1"
+ "$FULL_LTTNG_BIN" list "$SESSION_NAME" | grep "Tracing session" | grep -q "\[inactive\]"
+
+ ok $ret "Session \"$SESSION_NAME\" is inactive"
+}
+
+function test_start_session_action()
+{
+ local SESSION_NAME="my_triggered_session"
+ local TRIGGER_NAME="trigger1"
+ local TRACE_PATH=$(mktemp -d test-start-action-trace.XXXXXX)
+ local SYNC_AFTER_NOTIF_REGISTER_PATH=$(mktemp test-notif-register.XXXXXX)
+
+ diag "Start session action"
+
+ create_lttng_session_ok $SESSION_NAME "$TRACE_PATH"
+
+ enable_ust_lttng_event_ok $SESSION_NAME "tp:tptest"
+
+ lttng_session_is_inactive $SESSION_NAME
+
+ # Add `start-session` action to an event-rule condition _followed_ by
+ # a `notify` action.
+ lttng_add_trigger_ust_ok \
+ $TRIGGER_NAME \
+ --condition on-event -u "tp:tptest" \
+ --action start-session $SESSION_NAME \
+ --action notify
+
+ # Launch notification listener.
+ $NOTIFICATION_CLIENT_BIN \
+ --trigger $TRIGGER_NAME \
+ --sync-after-notif-register "$SYNC_AFTER_NOTIF_REGISTER_PATH"
+ notif_client_pid=$!
+
+ while [ ! -f "${SYNC_AFTER_NOTIF_REGISTER_PATH}" ]; do
+ sleep 0.5
+ done
+
+ # Artificially produce the desired event-rule condition.
+ $GEN_UST_EVENTS_TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT > /dev/null 2>&1
+
+ # notification-client will exit once it receives a notification.
+ wait $notif_client_pid
+ test "$?" -eq "0"
+ ok $? "notification client exited successfully"
+
+ # Test that the session has started.
+ lttng_session_is_active $SESSION_NAME
+
+ # Tearing down.
+ lttng_remove_trigger_ust_ok $TRIGGER_NAME
+ stop_lttng_tracing_ok $SESSION_NAME
+ destroy_lttng_session_ok $SESSION_NAME
+
+ rm -f "$SYNC_AFTER_NOTIF_REGISTER_PATH"
+ rm -rf "$TRACE_PATH"
+}
+
+function test_stop_session_action()
+{
+ local SESSION_NAME="my_triggered_session"
+ local TRIGGER_NAME="trigger1"
+ local TRACE_PATH=$(mktemp -d test-stop-action-trace.XXXXXX)
+ local SYNC_AFTER_NOTIF_REGISTER_PATH=$(mktemp test-notif-register.XXXXXX)
+
+ diag "Stop session action"
+ create_lttng_session_ok $SESSION_NAME "$TRACE_PATH"
+
+ enable_ust_lttng_event_ok $SESSION_NAME "tp:tptest"
+
+ start_lttng_tracing_ok $SESSION_NAME
+
+ lttng_session_is_active $SESSION_NAME
+
+ # Add `stop-session` action to an event-rule condition _followed_ by
+ # a `notify` action.
+ lttng_add_trigger_ust_ok \
+ $TRIGGER_NAME \
+ --condition on-event -u "tp:tptest" \
+ --action stop-session $SESSION_NAME \
+ --action notify
+
+ # Launch notification listener.
+ $NOTIFICATION_CLIENT_BIN \
+ --trigger $TRIGGER_NAME \
+ --sync-after-notif-register "$SYNC_AFTER_NOTIF_REGISTER_PATH"
+ notif_client_pid=$!
+
+ while [ ! -f "${SYNC_AFTER_NOTIF_REGISTER_PATH}" ]; do
+ sleep 0.5
+ done
+
+ # Artificially produce the desired event-rule condition.
+ $GEN_UST_EVENTS_TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT > /dev/null 2>&1
+
+ # notification-client will exit once it receives a notification.
+ wait $notif_client_pid
+ test "$?" -eq "0"
+ ok $? "notification client exited successfully"
+
+ # Test that the session has been stopped.
+ lttng_session_is_inactive $SESSION_NAME
+
+ # Tearing down.
+ lttng_remove_trigger_ust_ok $TRIGGER_NAME
+ destroy_lttng_session_ok $SESSION_NAME
+
+ rm -f "$SYNC_AFTER_NOTIF_REGISTER_PATH"
+ rm -rf "$TRACE_PATH"
+}
+
+ # MUST set TESTDIR before calling those functions
+plan_tests $NUM_TESTS
+
+print_test_banner "$TEST_DESC"
+
+start_lttng_sessiond_notap
+
+test_start_session_action
+test_stop_session_action
+
+stop_lttng_sessiond_notap
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+
+AM_CFLAGS += -I$(srcdir) -I$(top_srcdir)/tests/utils
+LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
+
+noinst_PROGRAMS = notification-client
+notification_client_SOURCES = notification-client.c
+notification_client_LDADD = $(LIBLTTNG_CTL) \
+ $(top_builddir)/tests/utils/libtestutils.la
--- /dev/null
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <lttng/condition/event-rule.h>
+#include <lttng/lttng.h>
+
+#include "utils.h"
+
+static struct option long_options[] =
+{
+ /* These options set a flag. */
+ {"trigger", required_argument, 0, 'i'},
+ {"sync-after-notif-register", required_argument, 0, 'a'},
+ {0, 0, 0, 0}
+};
+
+static bool action_group_contains_notify(
+ const struct lttng_action *action_group)
+{
+ unsigned int i, count;
+ enum lttng_action_status status =
+ lttng_action_group_get_count(action_group, &count);
+
+ if (status != LTTNG_ACTION_STATUS_OK) {
+ printf("Failed to get action count from action group\n");
+ exit(1);
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct lttng_action *action =
+ lttng_action_group_get_at_index(
+ action_group, i);
+ const enum lttng_action_type action_type =
+ lttng_action_get_type(action);
+
+ if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool is_expected_trigger_name(const char *expected_trigger_name,
+ struct lttng_notification *notification)
+{
+ int ret = false;
+ const struct lttng_evaluation *evaluation =
+ lttng_notification_get_evaluation(notification);
+ const enum lttng_condition_type type =
+ lttng_evaluation_get_type(evaluation);
+
+ switch (type) {
+ case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+ case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+ case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+ break;
+ case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+ {
+ const char *trigger_name;
+ enum lttng_evaluation_status evaluation_status;
+
+ evaluation_status =
+ lttng_evaluation_event_rule_get_trigger_name(
+ evaluation, &trigger_name);
+ if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
+ fprintf(stderr, "Failed to get trigger name of event rule notification\n");
+ ret = -1;
+ break;
+ }
+
+ ret = true;
+ break;
+ }
+ default:
+ fprintf(stderr, "Unknown notification type (%d)\n", type);
+ }
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ int option;
+ int option_index;
+ const char *expected_trigger_name = NULL;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int count, i, subcription_count = 0;
+ enum lttng_trigger_status trigger_status;
+ char *after_notif_register_file_path = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+
+ while ((option = getopt_long(argc, argv, "a:t:",
+ long_options, &option_index)) != -1) {
+ switch (option) {
+ case 'a':
+ after_notif_register_file_path = strdup(optarg);
+ break;
+ case 't':
+ expected_trigger_name = strdup(optarg);
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ default:
+ ret = -1;
+ goto end;
+ }
+ }
+
+ if (optind != argc) {
+ ret = -1;
+ goto end;
+ }
+
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ if (!notification_channel) {
+ fprintf(stderr, "Failed to create notification channel\n");
+ ret = -1;
+ goto end;
+ }
+
+ ret = lttng_list_triggers(&triggers);
+ if (ret != LTTNG_OK) {
+ fprintf(stderr, "Failed to list triggers\n");
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fprintf(stderr, "Failed to get trigger count\n");
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct lttng_trigger *trigger =
+ lttng_triggers_get_at_index(triggers, i);
+ const struct lttng_condition *condition =
+ lttng_trigger_get_const_condition(trigger);
+ const struct lttng_action *action =
+ lttng_trigger_get_const_action(trigger);
+ const enum lttng_action_type action_type =
+ lttng_action_get_type(action);
+ enum lttng_notification_channel_status channel_status;
+ const char *trigger_name = NULL;
+
+ lttng_trigger_get_name(trigger, &trigger_name);
+ if (strcmp(trigger_name, expected_trigger_name)) {
+ continue;
+ }
+
+ if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
+ action_group_contains_notify(action)) ||
+ action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
+ /* "The action of trigger is not notify, skipping. */
+ continue;
+ }
+
+ channel_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ if (channel_status) {
+ fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
+ trigger_name);
+ ret = -1;
+ goto end;
+ }
+
+ subcription_count++;
+ }
+
+ if (subcription_count == 0) {
+ printf("No matching trigger with a notify action found.\n");
+ ret = 0;
+ goto end;
+ }
+
+
+ /*
+ * We registered to the notification of our target trigger. We can now
+ * create the sync file to signify that we are ready.
+ */
+ ret = create_file(after_notif_register_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+
+ for (;;) {
+ struct lttng_notification *notification;
+ enum lttng_notification_channel_status channel_status;
+
+ channel_status =
+ lttng_notification_channel_get_next_notification(
+ notification_channel,
+ ¬ification);
+ switch (channel_status) {
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
+ printf("Dropped notification\n");
+ break;
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
+ ret = 0;
+ goto end;
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
+ break;
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
+ printf("Notification channel was closed by peer.\n");
+ break;
+ default:
+ fprintf(stderr, "A communication error occurred on the notification channel.\n");
+ ret = -1;
+ goto end;
+ }
+
+ ret = is_expected_trigger_name(expected_trigger_name,
+ notification);
+ lttng_notification_destroy(notification);
+ if (ret) {
+ ret = 0;
+ goto end;
+ }
+ }
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_notification_channel_destroy(notification_channel);
+ return !!ret;
+}