Implements the regression tests for the trigger action firing polices.
For now the focus is put on the notify action behavior. In the future,
the ability to fetch the number of time an action was enqueued for
execution and the number of type it was executed should greatly
facilitate this work. For now, use the notify action for minimal
regression testing.
gen-ust-events is modified to allow a caller to specify that an `end`
event should be emitted at the end of the program. This is used to
guaranteed that all previous event tracer notifications should be
received when the `end` event notification is received. Note that
ordering is guaranteed for delivery of tracer notification and
notification for a given process.
notificiation-client is modified to allow reception of N notifications
and to validate that it received the count it expects.
notificiation-client is modified to allow reception of N notifications
and to exit only when an `end` event notification is received. This
allow us validate the firing policy.
The tests are pretty straightforward. We register 2 triggers, one with
an event rule condition on `tp:tptest` and the other one with a event
rule condition on `tp:end`. From there we perform a phase of event hits
were we expect no notification except for the `tp:end` then we force a
single event hit were we expect a notification for `tp:tptest`. For the
fire every N policy, we rinse and repeat to validate the behaviour. For
the once after N, we simply do a third phase were we generate N events
and expect no notification.
Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Ia3c88f38dcca0389165e1416b06768338b2889b6
tests/regression/tools/relayd-grouping/Makefile
tests/regression/tools/clear/Makefile
tests/regression/tools/trigger/Makefile
+ tests/regression/tools/trigger/firing-policy/Makefile
tests/regression/tools/trigger/start-stop/Makefile
tests/regression/tools/trigger/utils/Makefile
tests/regression/ust/Makefile
ust/multi-lib/test_multi_lib \
ust/rotation-destroy-flush/test_rotation_destroy_flush \
tools/metadata/test_ust \
- tools/relayd-grouping/test_ust
+ tools/relayd-grouping/test_ust \
+ tools/trigger/firing-policy/test_ust_firing_policy
if IS_LINUX
TESTS += \
-SUBDIRS=utils start-stop
+SUBDIRS=utils start-stop firing-policy
noinst_SCRIPTS = test_add_trigger_cli \
test_list_triggers_cli \
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+
+noinst_SCRIPTS = test_ust_firing_policy
+
+EXTRA_DIST = test_ust_firing_policy
+
+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"
+NOTIFICATION_CLIENT_BIN="$CURDIR/../utils/notification-client"
+NUM_TESTS=19
+
+NR_ITER=10
+NR_USEC_WAIT=5
+
+function test_firing_policy_every_n()
+{
+ local SESSION_NAME="my_triggered_session"
+ local TRIGGER_NAME="trigger1"
+ local END_TRIGGER_NAME="end-trigger1"
+ local SYNC_AFTER_NOTIF_REGISTER_PATH
+
+ SYNC_AFTER_NOTIF_REGISTER_PATH=$(mktemp -u test-notif-register.XXXXXX)
+
+ diag "Every N firing policy"
+
+ # Add a trigger with a notify action with a policy to fire it every 5
+ # time the condition is met.
+ lttng_add_trigger_ok \
+ $TRIGGER_NAME \
+ --condition on-event -u "tp:tptest" \
+ --action notify \
+ --fire-every 5
+
+ # Add a trigger with a notify action for the tp:end event of the test
+ # application. This allow us to "delimit" the reception loop for the
+ # notification client ensuring that all events were hit and passed into
+ # the notification subsystem.
+ lttng_add_trigger_ok \
+ $END_TRIGGER_NAME \
+ --condition on-event -u "tp:end" \
+ --action notify
+
+ for i in $(seq 1 4); do
+ diag "Iteration $i of 4"
+ ## Phase 1
+ # Hit the trigger condition 4 time and validate that no (0)
+ # notification for that condition was received.
+ $NOTIFICATION_CLIENT_BIN \
+ --trigger $TRIGGER_NAME \
+ --sync-after-notif-register "$SYNC_AFTER_NOTIF_REGISTER_PATH" \
+ --count 0 \
+ --end-trigger "$END_TRIGGER_NAME" &
+ notif_client_pid=$!
+ while [ ! -f "${SYNC_AFTER_NOTIF_REGISTER_PATH}" ]; do
+ sleep 0.5
+ done
+
+ $GEN_UST_EVENTS_TESTAPP_BIN -i 4 -w $NR_USEC_WAIT --emit-end-event > /dev/null 2>&1
+
+ # notification-client will exit once it receives the end-trigger notification.
+ # Validation of the number of received notification is done by the
+ # notification client. Here it validate that it received 0 notifications.
+ wait $notif_client_pid
+ test "$?" -eq "0"
+ ok $? "notification client exited successfully"
+
+ ## Phase 2
+ # Hit the condition 1 time and validate that a notification is
+ # received.
+ rm -f "${SYNC_AFTER_NOTIF_REGISTER_PATH}"
+ $NOTIFICATION_CLIENT_BIN \
+ --trigger $TRIGGER_NAME \
+ --sync-after-notif-register "$SYNC_AFTER_NOTIF_REGISTER_PATH" \
+ --count 1 \
+ --end-trigger "$END_TRIGGER_NAME" &
+ 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 1 -w $NR_USEC_WAIT --emit-end-event > /dev/null 2>&1
+
+ # notification-client will exit once it receives the end-trigger notification.
+ # Validation of the number of received notification is done by the
+ # notification client. Here it validate that it received 1 notifications.
+ wait $notif_client_pid
+ test "$?" -eq "0"
+ ok $? "notification client exited successfully"
+
+ rm -f "${SYNC_AFTER_NOTIF_REGISTER_PATH}"
+ done
+
+ # Tearing down.
+ lttng_remove_trigger_ok $TRIGGER_NAME
+ lttng_remove_trigger_ok $END_TRIGGER_NAME
+
+ rm -f "$SYNC_AFTER_NOTIF_REGISTER_PATH"
+}
+
+function test_firing_policy_once_after_n()
+{
+ local SESSION_NAME="my_triggered_session"
+ local TRIGGER_NAME="trigger1"
+ local END_TRIGGER_NAME="end-trigger1"
+ local SYNC_AFTER_NOTIF_REGISTER_PATH
+
+ SYNC_AFTER_NOTIF_REGISTER_PATH=$(mktemp -u test-notif-register.XXXXXX)
+
+ diag "Once after N firing policy"
+
+ # Add a trigger with a notify action with a policy to fire it every 5
+ # time the condition is met.
+ lttng_add_trigger_ok \
+ $TRIGGER_NAME \
+ --condition on-event -u "tp:tptest" \
+ --action notify \
+ --fire-once-after 5
+
+ # Add a trigger with a notify action for the tp:end event of the test
+ # application. This allow us to "delimit" the reception loop for the
+ # notification client ensuring that all events were hit and passed into
+ # the notification subsystem.
+ lttng_add_trigger_ok \
+ $END_TRIGGER_NAME \
+ --condition on-event -u "tp:end" \
+ --action notify
+
+ ## Phase 1
+ # Hit the trigger condition 4 time and validate that no (0)
+ # notification for that condition was received.
+ $NOTIFICATION_CLIENT_BIN \
+ --trigger $TRIGGER_NAME \
+ --sync-after-notif-register "$SYNC_AFTER_NOTIF_REGISTER_PATH" \
+ --count 0 \
+ --end-trigger "$END_TRIGGER_NAME" &
+ 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 4 -w $NR_USEC_WAIT --emit-end-event > /dev/null 2>&1
+
+ # notification-client will exit once it receives the end-trigger notification.
+ # Validation of the number of received notification is done by the
+ # notification client. Here it validate that it received 0 notifications.
+ wait $notif_client_pid
+ test "$?" -eq "0"
+ ok $? "notification client exited successfully"
+
+ ## Phase 2
+ # Hit the condition 1 time and validate that a notification is
+ # received.
+ rm -f "${SYNC_AFTER_NOTIF_REGISTER_PATH}"
+ $NOTIFICATION_CLIENT_BIN \
+ --trigger $TRIGGER_NAME \
+ --sync-after-notif-register "$SYNC_AFTER_NOTIF_REGISTER_PATH" \
+ --count 1 \
+ --end-trigger "$END_TRIGGER_NAME" &
+ 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 1 -w $NR_USEC_WAIT --emit-end-event > /dev/null 2>&1
+
+ # notification-client will exit once it receives the end-trigger notification.
+ # Validation of the number of received notification is done by the
+ # notification client. Here it validate that it received 1 notifications.
+ wait $notif_client_pid
+ test "$?" -eq "0"
+ ok $? "notification client exited successfully"
+
+ ## Phase 3
+ # Hit the condition N time and validate that no (0) notification is
+ # received.
+ rm -f "${SYNC_AFTER_NOTIF_REGISTER_PATH}"
+ $NOTIFICATION_CLIENT_BIN \
+ --trigger $TRIGGER_NAME \
+ --sync-after-notif-register "$SYNC_AFTER_NOTIF_REGISTER_PATH" \
+ --count 0 \
+ --end-trigger "$END_TRIGGER_NAME" &
+ 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 --emit-end-event > /dev/null 2>&1
+
+ # notification-client will exit once it receives the end-trigger notification.
+ # Validation of the number of received notification is done by the
+ # notification client. Here it validate that it received 0 notifications.
+ wait $notif_client_pid
+ test "$?" -eq "0"
+ ok $? "notification client exited successfully"
+
+ # Tearing down.
+ lttng_remove_trigger_ok $TRIGGER_NAME
+ lttng_remove_trigger_ok $END_TRIGGER_NAME
+
+ rm -f "$SYNC_AFTER_NOTIF_REGISTER_PATH"
+}
+
+ # MUST set TESTDIR before calling those functions
+plan_tests $NUM_TESTS
+
+print_test_banner "$TEST_DESC"
+
+start_lttng_sessiond_notap
+
+test_firing_policy_every_n
+test_firing_policy_once_after_n
+
+stop_lttng_sessiond_notap
/* These options set a flag. */
{"trigger", required_argument, 0, 't'},
{"sync-after-notif-register", required_argument, 0, 'a'},
+ /* Default alue for count is 1 */
+ {"count", required_argument, 0, 'b'},
+ /*
+ * When end-trigger is present the reception loop is exited only when a
+ * notification matching the end trigger is received.
+ * Otherwise the loop is exited when the count of notification received
+ * for `trigger` math the `count` argument.
+ */
+ {"end-trigger", required_argument, 0, 'c'},
{0, 0, 0, 0}
};
int option;
int option_index;
const char *expected_trigger_name = NULL;
+ const char *end_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;
+ int expected_notifications = 1, notification_count = 0;
- while ((option = getopt_long(argc, argv, "a:t:",
- long_options, &option_index)) != -1) {
+ while ((option = getopt_long(argc, argv, "a:b:c:t:", long_options,
+ &option_index)) != -1) {
switch (option) {
case 'a':
after_notif_register_file_path = strdup(optarg);
break;
+ case 'b':
+ expected_notifications = atoi(optarg);
+ break;
+ case 'c':
+ end_trigger_name = strdup(optarg);
+ break;
case 't':
expected_trigger_name = strdup(optarg);
break;
lttng_trigger_get_name(trigger, &trigger_name);
if (strcmp(trigger_name, expected_trigger_name)) {
- continue;
+ /* Might match the end event trigger */
+ if (end_trigger_name != NULL &&
+ strcmp(trigger_name,
+ end_trigger_name)) {
+ continue;
+ }
}
-
if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
action_group_contains_notify(action)) ||
action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
}
if (subcription_count == 0) {
- printf("No matching trigger with a notify action found.\n");
- ret = 0;
+ fprintf(stderr, "No matching trigger with a notify action found.\n");
+ ret = -1;
goto end;
}
+ if (end_trigger_name != NULL && subcription_count != 2) {
+ fprintf(stderr, "No matching end event trigger with a notify action found.\n");
+ ret = -1;
+ goto end;
+ }
/*
* We registered to the notification of our target trigger. We can now
goto end;
}
+ /* Early exit check. */
+ if (end_trigger_name != NULL &&
+ is_trigger_name(end_trigger_name,
+ notification)) {
+ /* Exit the loop immediately. */
+ printf("Received end event notification from trigger %s\n",
+ end_trigger_name);
+ lttng_notification_destroy(notification);
+ goto evaluate_success;
+ }
+
ret = is_trigger_name(expected_trigger_name, notification);
lttng_notification_destroy(notification);
if (!ret) {
ret = -1;
goto end;
- } else {
- ret = 0;
- goto end;
+ }
+
+ printf("Received event notification from trigger %s\n",
+ expected_trigger_name);
+ notification_count++;
+ if (end_trigger_name == NULL &&
+ expected_notifications == notification_count) {
+ /*
+ * Here the loop exit is controlled by the number of
+ * notification and not by the reception of the end
+ * event trigger notification. This represent the
+ * default behavior.
+ *
+ */
+ goto evaluate_success;
}
}
+
+evaluate_success:
+ if (expected_notifications == notification_count) {
+ /* Success */
+ ret = 0;
+ } else {
+ fprintf(stderr, "Expected %d notification got %d\n",
+ expected_notifications, notification_count);
+ ret = 1;
+ }
+
end:
lttng_triggers_destroy(triggers);
lttng_notification_channel_destroy(notification_channel);
{"sync-before-last-event-touch", required_argument, 0, 'c'},
{"sync-before-exit", required_argument, 0, 'd'},
{"sync-before-exit-touch", required_argument, 0, 'e'},
+ {"emit-end-event", no_argument, 0, 'f'},
{0, 0, 0, 0}
};
char *before_exit_file_path_touch = NULL;
/* Wait on file before exiting */
char *before_exit_file_path = NULL;
+ /* Emit an end event */
+ bool emit_end_event = false;
for (i = 0; i < 3; i++) {
net_values[i] = htonl(net_values[i]);
}
- while ((option = getopt_long(argc, argv, "i:w:a:b:c:d:",
- long_options, &option_index)) != -1) {
+ while ((option = getopt_long(argc, argv, "i:w:a:b:c:d:e:f",
+ long_options, &option_index)) != -1) {
switch (option) {
case 'a':
after_first_event_file_path = strdup(optarg);
case 'e':
before_exit_file_path_touch = strdup(optarg);
break;
+ case 'f':
+ emit_end_event = true;
+ break;
case 'i':
nr_iter = atoi(optarg);
break;
}
}
+ if (emit_end_event) {
+ tracepoint(tp, end);
+ }
+
if (before_exit_file_path_touch) {
ret = create_file(before_exit_file_path_touch);
if (ret != 0) {
)
)
+TRACEPOINT_EVENT(tp, end,
+ TP_ARGS(),
+ TP_FIELDS(
+ )
+)
+
#endif /* _TRACEPOINT_TP_H */
#undef TRACEPOINT_INCLUDE