actions: list: Add `for_each_action_{const, mutable}()` macros
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Wed, 23 Jun 2021 16:33:18 +0000 (12:33 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 1 Jun 2023 14:10:05 +0000 (10:10 -0400)
Accessing all the inner actions of a action list in a loop is a common
access pattern. This commit adds 2 `for_each` macros to iterate over all
elements either using a const or a mutable pointer.

Add a few unit tests for the list action to test these macros.

Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I9aff0b81e1f782b5d20c3fcb82ee7028da8dd810

.clang-format
include/lttng/action/list-internal.hpp
src/bin/lttng-sessiond/action-executor.cpp
src/bin/lttng-sessiond/notification-thread-events.cpp
src/bin/lttng/commands/list_triggers.cpp
tests/regression/tools/trigger/utils/Makefile.am
tests/regression/tools/trigger/utils/notification-client.c [deleted file]
tests/regression/tools/trigger/utils/notification-client.cpp [new file with mode: 0644]
tests/unit/test_action.cpp

index fd362abbad0ebdad4b06e147c7cb2cfa501e2a4e..f854e32c923ac59c8f83bf0a33d6b0bba42f83ab 100644 (file)
@@ -52,6 +52,8 @@ ForEachMacros:
   - 'cds_lfht_for_each_duplicate'
   - 'cds_list_for_each_entry'
   - 'cds_list_for_each_entry_safe'
+  - 'for_each_action_mutable'
+  - 'for_each_action_const'
 
 IncludeBlocks: Regroup
 IncludeCategories:
index 7282ab7e4599ebc58a90d94c8cfbc12715233e1b..53cab5897eb1b17c7286356ef748bae3b78a3a01 100644 (file)
@@ -10,6 +10,9 @@
 
 #include <common/macros.hpp>
 
+#include <lttng/lttng-error.h>
+
+#include <assert.h>
 #include <sys/types.h>
 
 struct lttng_action;
@@ -38,4 +41,19 @@ lttng_action_list_mi_serialize(const struct lttng_trigger *trigger,
                               const struct mi_lttng_error_query_callbacks *error_query_callbacks,
                               struct lttng_dynamic_array *action_path_indexes);
 
+#define for_each_action_const(__action_element, __action_list)                                 \
+       assert(lttng_action_get_type(__action_list) == LTTNG_ACTION_TYPE_LIST);                \
+                                                                                               \
+       for (unsigned int __action_idx = 0;                                                    \
+            (__action_element = lttng_action_list_get_at_index(__action_list, __action_idx)); \
+            __action_idx++)
+
+#define for_each_action_mutable(__action_element, __action_list)                               \
+       assert(lttng_action_get_type(__action_list) == LTTNG_ACTION_TYPE_LIST);                \
+                                                                                               \
+       for (unsigned int __action_idx = 0;                                                    \
+            (__action_element =                                                               \
+                     lttng_action_list_borrow_mutable_at_index(__action_list, __action_idx)); \
+            __action_idx++)
+
 #endif /* LTTNG_ACTION_LIST_INTERNAL_H */
index 31683547b1340260579fa4016c29b6130b2080f5..a9476bd31dd4a95636a70e38d5f169c6db121c62 100644 (file)
@@ -992,16 +992,11 @@ static int add_action_to_subitem_array(struct lttng_action *action,
        LTTNG_ASSERT(subitems);
 
        if (type == LTTNG_ACTION_TYPE_LIST) {
-               unsigned int count, i;
+               struct lttng_action *inner_action = NULL;
 
-               status = lttng_action_list_get_count(action, &count);
-               LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
-
-               for (i = 0; i < count; i++) {
-                       struct lttng_action *inner_action = nullptr;
-
-                       inner_action = lttng_action_list_borrow_mutable_at_index(action, i);
+               for_each_action_mutable (inner_action, action) {
                        LTTNG_ASSERT(inner_action);
+
                        ret = add_action_to_subitem_array(inner_action, subitems);
                        if (ret) {
                                goto end;
index 58a38cce191d7b720861d14e8aa96161cfc7a008..ab0fa84ce0d197dad29eb9c351acbb853feaa89f 100644 (file)
@@ -2502,9 +2502,8 @@ end:
 static bool is_trigger_action_notify(const struct lttng_trigger *trigger)
 {
        bool is_notify = false;
-       unsigned int i, count;
-       enum lttng_action_status action_status;
        const struct lttng_action *action = lttng_trigger_get_const_action(trigger);
+       const struct lttng_action *inner_action;
        enum lttng_action_type action_type;
 
        LTTNG_ASSERT(action);
@@ -2516,14 +2515,8 @@ static bool is_trigger_action_notify(const struct lttng_trigger *trigger)
                goto end;
        }
 
-       action_status = lttng_action_list_get_count(action, &count);
-       LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-
-       for (i = 0; i < count; i++) {
-               const struct lttng_action *inner_action = lttng_action_list_get_at_index(action, i);
-
-               action_type = lttng_action_get_type(inner_action);
-               if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
+       for_each_action_const (inner_action, action) {
+               if (lttng_action_get_type(inner_action) == LTTNG_ACTION_TYPE_NOTIFY) {
                        is_notify = true;
                        goto end;
                }
index d3961539083eb1cb908cee896a4ec2f4c2b1d1d4..c9c6c265de053fb66cc3123c338ca6efa42057ac 100644 (file)
 #include "common/argpar/argpar.h"
 #include "common/dynamic-array.hpp"
 #include "common/mi-lttng.hpp"
+#include "lttng/action/list-internal.hpp"
 
-#include <stdio.h>
 /* For lttng_condition_type_str(). */
 #include "lttng/condition/condition-internal.hpp"
 #include "lttng/condition/event-rule-matches-internal.hpp"
 #include "lttng/condition/event-rule-matches.h"
+
 /* For lttng_domain_type_str(). */
 #include "lttng/domain-internal.hpp"
+
 /* For lttng_event_rule_kernel_syscall_emission_site_str() */
 #include "../loglevel.hpp"
 #include "lttng/event-rule/kernel-syscall-internal.hpp"
@@ -1022,21 +1024,14 @@ static void print_one_trigger(const struct lttng_trigger *trigger)
        action = lttng_trigger_get_const_action(trigger);
        action_type = lttng_action_get_type(action);
        if (action_type == LTTNG_ACTION_TYPE_LIST) {
-               unsigned int count, i;
-               enum lttng_action_status action_status;
+               const struct lttng_action *subaction;
+               uint64_t action_path_index = 0;
 
                MSG("  actions:");
-
-               action_status = lttng_action_list_get_count(action, &count);
-               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-
-               for (i = 0; i < count; i++) {
-                       const uint64_t action_path_index = i;
-                       const struct lttng_action *subaction =
-                               lttng_action_list_get_at_index(action, i);
-
+               for_each_action_const (subaction, action) {
                        _MSG("    ");
                        print_one_action(trigger, subaction, &action_path_index, 1);
+                       action_path_index++;
                }
        } else {
                _MSG(" action:");
index a6a0258d4188df730f16bb18e73ad67ad8ae7e7a..3522aaec37d01dee0e13730426b28177cb265c99 100644 (file)
@@ -7,7 +7,7 @@ noinst_PROGRAMS = \
        notification-client \
        register-some-triggers
 
-notification_client_SOURCES = notification-client.c
+notification_client_SOURCES = notification-client.cpp
 notification_client_LDADD = $(LIBLTTNG_CTL) \
        $(top_builddir)/tests/utils/libtestutils.la
 
diff --git a/tests/regression/tools/trigger/utils/notification-client.c b/tests/regression/tools/trigger/utils/notification-client.c
deleted file mode 100644 (file)
index b656d72..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include "utils.h"
-
-#include <lttng/condition/event-rule-matches.h>
-#include <lttng/lttng.h>
-
-#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>
-
-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 }
-};
-
-static bool action_list_contains_notify(const struct lttng_action *action_list)
-{
-       unsigned int i, count;
-       enum lttng_action_status status = lttng_action_list_get_count(action_list, &count);
-
-       if (status != LTTNG_ACTION_STATUS_OK) {
-               printf("Failed to get action count from action list\n");
-               exit(1);
-       }
-
-       for (i = 0; i < count; i++) {
-               const struct lttng_action *action = lttng_action_list_get_at_index(action_list, i);
-               const enum lttng_action_type action_type = lttng_action_get_type(action);
-
-               if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
-                       return true;
-               }
-       }
-       return false;
-}
-
-/* Only expects named triggers. */
-static bool is_trigger_name(const char *expected_trigger_name,
-                           struct lttng_notification *notification)
-{
-       const char *trigger_name = NULL;
-       enum lttng_trigger_status trigger_status;
-       const struct lttng_trigger *trigger;
-       bool names_match;
-
-       trigger = lttng_notification_get_trigger(notification);
-       if (!trigger) {
-               fprintf(stderr, "Failed to get trigger from notification\n");
-               names_match = false;
-               goto end;
-       }
-
-       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               fprintf(stderr, "Failed to get name from notification's trigger\n");
-               names_match = false;
-               goto end;
-       }
-
-       names_match = strcmp(expected_trigger_name, trigger_name) == 0;
-       if (!names_match) {
-               fprintf(stderr,
-                       "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
-                       trigger_name,
-                       expected_trigger_name);
-       }
-end:
-       return names_match;
-}
-
-int main(int argc, char **argv)
-{
-       int ret;
-       int option;
-       int option_index;
-       char *expected_trigger_name = NULL;
-       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: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;
-               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");
-               ret = -1;
-               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;
-       }
-
-       /* Look for the trigger we want to subscribe to. */
-       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) != 0) {
-                       /* Might match the end event trigger */
-                       if (end_trigger_name != NULL &&
-                           strcmp(trigger_name, end_trigger_name) != 0) {
-                               continue;
-                       }
-               }
-               if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
-                      action_list_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) {
-               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
-        * 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, &notification);
-               switch (channel_status) {
-               case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
-                       printf("Dropped notification\n");
-                       ret = -1;
-                       goto end;
-               case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
-                       ret = -1;
-                       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;
-               }
-
-               /* 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;
-               }
-
-               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);
-       free(after_notif_register_file_path);
-       free(end_trigger_name);
-       free(expected_trigger_name);
-       return !!ret;
-}
diff --git a/tests/regression/tools/trigger/utils/notification-client.cpp b/tests/regression/tools/trigger/utils/notification-client.cpp
new file mode 100644 (file)
index 0000000..02dc062
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include "utils.h"
+
+#include <lttng/action/list-internal.hpp>
+#include <lttng/condition/event-rule-matches.h>
+#include <lttng/lttng.h>
+
+#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>
+
+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 }
+};
+
+static bool action_list_contains_notify(const struct lttng_action *action_list)
+{
+       const struct lttng_action *sub_action;
+
+       for_each_action_const (sub_action, action_list) {
+               if (lttng_action_get_type(sub_action) == LTTNG_ACTION_TYPE_NOTIFY) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+/* Only expects named triggers. */
+static bool is_trigger_name(const char *expected_trigger_name,
+                           struct lttng_notification *notification)
+{
+       const char *trigger_name = NULL;
+       enum lttng_trigger_status trigger_status;
+       const struct lttng_trigger *trigger;
+       bool names_match;
+
+       trigger = lttng_notification_get_trigger(notification);
+       if (!trigger) {
+               fprintf(stderr, "Failed to get trigger from notification\n");
+               names_match = false;
+               goto end;
+       }
+
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fprintf(stderr, "Failed to get name from notification's trigger\n");
+               names_match = false;
+               goto end;
+       }
+
+       names_match = strcmp(expected_trigger_name, trigger_name) == 0;
+       if (!names_match) {
+               fprintf(stderr,
+                       "Got an unexpected trigger name: name = '%s', expected name = '%s'\n",
+                       trigger_name,
+                       expected_trigger_name);
+       }
+end:
+       return names_match;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       int option;
+       int option_index;
+       char *expected_trigger_name = NULL;
+       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: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;
+               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");
+               ret = -1;
+               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;
+       }
+
+       /* Look for the trigger we want to subscribe to. */
+       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) != 0) {
+                       /* Might match the end event trigger */
+                       if (end_trigger_name != NULL &&
+                           strcmp(trigger_name, end_trigger_name) != 0) {
+                               continue;
+                       }
+               }
+               if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
+                      action_list_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) {
+               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
+        * 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, &notification);
+               switch (channel_status) {
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
+                       printf("Dropped notification\n");
+                       ret = -1;
+                       goto end;
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
+                       ret = -1;
+                       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;
+               }
+
+               /* 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;
+               }
+
+               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);
+       free(after_notif_register_file_path);
+       free(end_trigger_name);
+       free(expected_trigger_name);
+       return !!ret;
+}
index c54b0278dbc4d92b9570160bda86384b954e5248..131a3af1d6aef3ef219e3183e3fdae0060b6522d 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <lttng/action/action-internal.hpp>
 #include <lttng/action/action.h>
+#include <lttng/action/list-internal.hpp>
 #include <lttng/action/notify.h>
 #include <lttng/action/rate-policy-internal.hpp>
 #include <lttng/action/rate-policy.h>
@@ -33,7 +34,7 @@ int lttng_opt_quiet = 1;
 int lttng_opt_verbose;
 int lttng_opt_mi;
 
-#define NUM_TESTS 60
+#define NUM_TESTS 71
 
 static void test_action_notify()
 {
@@ -98,7 +99,95 @@ static void test_action_notify()
        lttng_payload_reset(&payload);
 }
 
-static void test_action_rotate_session()
+static void test_action_list(void)
+{
+       int ret, action_idx;
+       struct lttng_action *list_action = NULL, *list_action_from_buffer = NULL,
+                           *mut_inner_action = NULL, *stop_session_action = NULL,
+                           *notify_action = NULL, *start_session_action = NULL;
+       const struct lttng_action *const_inner_action;
+       struct lttng_payload payload;
+
+       lttng_payload_init(&payload);
+
+       list_action = lttng_action_list_create();
+       ok(list_action, "Create list action");
+       ok(lttng_action_get_type(list_action) == LTTNG_ACTION_TYPE_LIST,
+          "Action has type LTTNG_ACTION_TYPE_LIST");
+
+       start_session_action = lttng_action_start_session_create();
+       (void) lttng_action_start_session_set_session_name(start_session_action, "une-session");
+
+       stop_session_action = lttng_action_stop_session_create();
+       (void) lttng_action_stop_session_set_session_name(stop_session_action, "une-autre-session");
+       notify_action = lttng_action_notify_create();
+
+       lttng_action_list_add_action(list_action, start_session_action);
+       lttng_action_list_add_action(list_action, stop_session_action);
+       lttng_action_list_add_action(list_action, notify_action);
+
+       ret = lttng_action_serialize(list_action, &payload);
+       ok(ret == 0, "Action list serialized");
+
+       {
+               struct lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
+               (void) lttng_action_create_from_payload(&view, &list_action_from_buffer);
+       }
+       ok(list_action_from_buffer, "Notify action created from payload is non-null");
+
+       ok(lttng_action_is_equal(list_action, list_action_from_buffer),
+          "Serialized and de-serialized list action are equal");
+
+       action_idx = 0;
+       for_each_action_const (const_inner_action, list_action) {
+               enum lttng_action_type inner_action_type =
+                       lttng_action_get_type(const_inner_action);
+               switch (action_idx) {
+               case 0:
+                       ok(inner_action_type == LTTNG_ACTION_TYPE_START_SESSION,
+                          "First inner action of action list is `start-session` action");
+                       break;
+               case 1:
+                       ok(inner_action_type == LTTNG_ACTION_TYPE_STOP_SESSION,
+                          "Second inner action of action list is `stop-session` action");
+                       break;
+               case 2:
+                       ok(inner_action_type == LTTNG_ACTION_TYPE_NOTIFY,
+                          "Third inner action of action list is `notify` action");
+                       break;
+               }
+               action_idx++;
+       }
+
+       action_idx = 0;
+       for_each_action_mutable (mut_inner_action, list_action) {
+               enum lttng_action_type inner_action_type = lttng_action_get_type(mut_inner_action);
+               switch (action_idx) {
+               case 0:
+                       ok(inner_action_type == LTTNG_ACTION_TYPE_START_SESSION,
+                          "First inner action of action list is `start-session` action");
+                       break;
+               case 1:
+                       ok(inner_action_type == LTTNG_ACTION_TYPE_STOP_SESSION,
+                          "Second inner action of action list is `stop-session` action");
+                       break;
+               case 2:
+                       ok(inner_action_type == LTTNG_ACTION_TYPE_NOTIFY,
+                          "Third inner action of action list is `notify` action");
+                       break;
+               }
+               action_idx++;
+       }
+
+       lttng_action_destroy(list_action);
+       lttng_action_destroy(list_action_from_buffer);
+       lttng_action_destroy(start_session_action);
+       lttng_action_destroy(stop_session_action);
+       lttng_action_destroy(notify_action);
+       lttng_payload_reset(&payload);
+}
+
+static void test_action_rotate_session(void)
 {
        int ret;
        enum lttng_action_status status;
@@ -458,6 +547,7 @@ int main()
 {
        plan_tests(NUM_TESTS);
        test_action_notify();
+       test_action_list();
        test_action_rotate_session();
        test_action_start_session();
        test_action_stop_session();
This page took 0.035893 seconds and 4 git commands to generate.