tests: trigger action firing policy
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Tue, 30 Mar 2021 02:00:37 +0000 (22:00 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 18 Apr 2021 23:28:57 +0000 (19:28 -0400)
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

configure.ac
tests/regression/Makefile.am
tests/regression/tools/trigger/Makefile.am
tests/regression/tools/trigger/firing-policy/Makefile.am [new file with mode: 0644]
tests/regression/tools/trigger/firing-policy/test_ust_firing_policy [new file with mode: 0755]
tests/regression/tools/trigger/utils/notification-client.c
tests/utils/testapp/gen-ust-events/gen-ust-events.c
tests/utils/testapp/gen-ust-events/tp.h

index 69914737241131baf8dd15d9d9d45e71d2a344c9..5a75c1efa532d71ff93b73569396d8468e37fb17 100644 (file)
@@ -1162,6 +1162,7 @@ AC_CONFIG_FILES([
        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
index 7970695fe9040f5017797f68536e915bb415c9dc..c66f64d887801fa7d9e49e5ff6d1189fc4555d4e 100644 (file)
@@ -73,7 +73,8 @@ TESTS += ust/before-after/test_before_after \
        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 += \
index 378bf8b5da99065f9b356c7eb64f046d753e0f87..914634a0425667212fe0d22dd18190290212bac3 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=utils start-stop
+SUBDIRS=utils start-stop firing-policy
 
 noinst_SCRIPTS = test_add_trigger_cli \
        test_list_triggers_cli \
diff --git a/tests/regression/tools/trigger/firing-policy/Makefile.am b/tests/regression/tools/trigger/firing-policy/Makefile.am
new file mode 100644 (file)
index 0000000..14d84cb
--- /dev/null
@@ -0,0 +1,19 @@
+# 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
diff --git a/tests/regression/tools/trigger/firing-policy/test_ust_firing_policy b/tests/regression/tools/trigger/firing-policy/test_ust_firing_policy
new file mode 100755 (executable)
index 0000000..d92dacc
--- /dev/null
@@ -0,0 +1,226 @@
+#!/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
index 7803fd51dac96eca02d4b05a9f56bc3c6f152ae0..904d7e5650c90661bf3dfa524cb837ce266c58c2 100644 (file)
@@ -24,6 +24,15 @@ static struct option long_options[] =
        /* 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}
 };
 
@@ -90,18 +99,26 @@ int main(int argc, char **argv)
        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;
@@ -156,9 +173,13 @@ int main(int argc, char **argv)
 
                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)) {
@@ -179,11 +200,16 @@ int main(int argc, char **argv)
        }
 
        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
@@ -222,16 +248,50 @@ int main(int argc, char **argv)
                        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);
index df1e58e417fa5f464b50a01f52fc2e3a97755881..57c33f59728125fef76b1e79a58d978ba479d5e5 100644 (file)
@@ -38,6 +38,7 @@ static struct option long_options[] =
        {"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}
 };
 
@@ -65,13 +66,15 @@ int main(int argc, char **argv)
        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);
@@ -88,6 +91,9 @@ int main(int argc, char **argv)
                case 'e':
                        before_exit_file_path_touch = strdup(optarg);
                        break;
+               case 'f':
+                       emit_end_event = true;
+                       break;
                case 'i':
                        nr_iter = atoi(optarg);
                        break;
@@ -174,6 +180,10 @@ int main(int argc, char **argv)
                }
        }
 
+       if (emit_end_event) {
+               tracepoint(tp, end);
+       }
+
        if (before_exit_file_path_touch) {
                ret = create_file(before_exit_file_path_touch);
                if (ret != 0) {
index 6b12a86ac7cc0bd3e4ee41ac316ce656750c77a1..6f22887cfbac098e907e48dafa6b43c114b62ce9 100644 (file)
@@ -60,6 +60,12 @@ TRACEPOINT_EVENT(tp, tptest,
        )
 )
 
+TRACEPOINT_EVENT(tp, end,
+       TP_ARGS(),
+       TP_FIELDS(
+       )
+)
+
 #endif /* _TRACEPOINT_TP_H */
 
 #undef TRACEPOINT_INCLUDE
This page took 0.048268 seconds and 4 git commands to generate.