From 6ffce1f5bbc5c3e956bc91ce801c779588bf37af Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Mon, 29 Mar 2021 22:00:37 -0400 Subject: [PATCH] tests: trigger action firing policy MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jérémie Galarneau Change-Id: Ia3c88f38dcca0389165e1416b06768338b2889b6 --- configure.ac | 1 + tests/regression/Makefile.am | 3 +- tests/regression/tools/trigger/Makefile.am | 2 +- .../tools/trigger/firing-policy/Makefile.am | 19 ++ .../firing-policy/test_ust_firing_policy | 226 ++++++++++++++++++ .../tools/trigger/utils/notification-client.c | 78 +++++- .../testapp/gen-ust-events/gen-ust-events.c | 14 +- tests/utils/testapp/gen-ust-events/tp.h | 6 + 8 files changed, 336 insertions(+), 13 deletions(-) create mode 100644 tests/regression/tools/trigger/firing-policy/Makefile.am create mode 100755 tests/regression/tools/trigger/firing-policy/test_ust_firing_policy diff --git a/configure.ac b/configure.ac index 699147372..5a75c1efa 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/tests/regression/Makefile.am b/tests/regression/Makefile.am index 7970695fe..c66f64d88 100644 --- a/tests/regression/Makefile.am +++ b/tests/regression/Makefile.am @@ -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 += \ diff --git a/tests/regression/tools/trigger/Makefile.am b/tests/regression/tools/trigger/Makefile.am index 378bf8b5d..914634a04 100644 --- a/tests/regression/tools/trigger/Makefile.am +++ b/tests/regression/tools/trigger/Makefile.am @@ -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 index 000000000..14d84cbd2 --- /dev/null +++ b/tests/regression/tools/trigger/firing-policy/Makefile.am @@ -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 index 000000000..d92dacc21 --- /dev/null +++ b/tests/regression/tools/trigger/firing-policy/test_ust_firing_policy @@ -0,0 +1,226 @@ +#!/bin/bash +# +# Copyright (C) 2020 Francis Deslauriers +# +# 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 diff --git a/tests/regression/tools/trigger/utils/notification-client.c b/tests/regression/tools/trigger/utils/notification-client.c index 7803fd51d..904d7e565 100644 --- a/tests/regression/tools/trigger/utils/notification-client.c +++ b/tests/regression/tools/trigger/utils/notification-client.c @@ -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); diff --git a/tests/utils/testapp/gen-ust-events/gen-ust-events.c b/tests/utils/testapp/gen-ust-events/gen-ust-events.c index df1e58e41..57c33f597 100644 --- a/tests/utils/testapp/gen-ust-events/gen-ust-events.c +++ b/tests/utils/testapp/gen-ust-events/gen-ust-events.c @@ -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) { diff --git a/tests/utils/testapp/gen-ust-events/tp.h b/tests/utils/testapp/gen-ust-events/tp.h index 6b12a86ac..6f22887cf 100644 --- a/tests/utils/testapp/gen-ust-events/tp.h +++ b/tests/utils/testapp/gen-ust-events/tp.h @@ -60,6 +60,12 @@ TRACEPOINT_EVENT(tp, tptest, ) ) +TRACEPOINT_EVENT(tp, end, + TP_ARGS(), + TP_FIELDS( + ) +) + #endif /* _TRACEPOINT_TP_H */ #undef TRACEPOINT_INCLUDE -- 2.34.1