tests: compile some tools/tests as C++
authorSimon Marchi <simon.marchi@efficios.com>
Mon, 6 Sep 2021 13:45:35 +0000 (09:45 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 18 Nov 2021 00:14:12 +0000 (19:14 -0500)
These tests use things from the common libs, or at least include header
files from src/common.  These files are going to contain C++-specific
things in a following commit, so it's easier if we compile them
tools/tests as C++.

Change-Id: Ib99f2373beb414c50eaa10b35e0d895bc37e4e64
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
50 files changed:
doc/examples/trigger-condition-event-matches/Makefile.am
doc/examples/trigger-condition-event-matches/notification-client.c [deleted file]
doc/examples/trigger-condition-event-matches/notification-client.cpp [new file with mode: 0644]
tests/regression/tools/live/Makefile.am
tests/regression/tools/live/live_test.c [deleted file]
tests/regression/tools/live/live_test.cpp [new file with mode: 0644]
tests/regression/tools/notification/Makefile.am
tests/regression/tools/notification/consumer_testpoints.cpp
tests/regression/tools/notification/notification.c [deleted file]
tests/regression/tools/notification/notification.cpp [new file with mode: 0644]
tests/regression/tools/trigger/hidden/Makefile.am
tests/regression/tools/trigger/hidden/hidden_trigger.c [deleted file]
tests/regression/tools/trigger/hidden/hidden_trigger.cpp [new file with mode: 0644]
tests/regression/tools/trigger/name/Makefile.am
tests/regression/tools/trigger/name/trigger_name.c [deleted file]
tests/regression/tools/trigger/name/trigger_name.cpp [new file with mode: 0644]
tests/regression/tools/trigger/utils/Makefile.am
tests/regression/tools/trigger/utils/register-some-triggers.c [deleted file]
tests/regression/tools/trigger/utils/register-some-triggers.cpp [new file with mode: 0644]
tests/utils/Makefile.am
tests/utils/testapp/gen-ns-events/Makefile.am
tests/utils/testapp/gen-ns-events/gen-ns-events.c [deleted file]
tests/utils/testapp/gen-ns-events/gen-ns-events.cpp [new file with mode: 0644]
tests/utils/testapp/gen-syscall-events/Makefile.am
tests/utils/testapp/gen-syscall-events/gen-syscall-events.c [deleted file]
tests/utils/testapp/gen-syscall-events/gen-syscall-events.cpp [new file with mode: 0644]
tests/utils/testapp/gen-ust-events-ns/Makefile.am
tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns.c [deleted file]
tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns.cpp [new file with mode: 0644]
tests/utils/testapp/gen-ust-events/Makefile.am
tests/utils/testapp/gen-ust-events/gen-ust-events.c [deleted file]
tests/utils/testapp/gen-ust-events/gen-ust-events.cpp [new file with mode: 0644]
tests/utils/testapp/gen-ust-nevents-str/Makefile.am
tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str.c [deleted file]
tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str.cpp [new file with mode: 0644]
tests/utils/testapp/gen-ust-nevents/Makefile.am
tests/utils/testapp/gen-ust-nevents/gen-ust-nevents.c [deleted file]
tests/utils/testapp/gen-ust-nevents/gen-ust-nevents.cpp [new file with mode: 0644]
tests/utils/testapp/gen-ust-tracef/Makefile.am
tests/utils/testapp/gen-ust-tracef/gen-ust-tracef.c [deleted file]
tests/utils/testapp/gen-ust-tracef/gen-ust-tracef.cpp [new file with mode: 0644]
tests/utils/testapp/signal-helper.h
tests/utils/utils.c [deleted file]
tests/utils/utils.cpp [new file with mode: 0644]
tests/utils/utils.h
tests/utils/xml-utils/Makefile.am
tests/utils/xml-utils/extract_xml.c [deleted file]
tests/utils/xml-utils/extract_xml.cpp [new file with mode: 0644]
tests/utils/xml-utils/validate_xml.c [deleted file]
tests/utils/xml-utils/validate_xml.cpp [new file with mode: 0644]

index bace545b9371e2e8401f9f9ace63120f5314bd5e..cb5512ed0e6e7737cdef4465e606e9671cb5442c 100644 (file)
@@ -15,7 +15,7 @@ libtracepoint_trigger_example_a_SOURCES = tracepoint-trigger-example.c tracepoin
 instrumented_app_SOURCES = instrumented-app.c
 instrumented_app_LDADD = libtracepoint-trigger-example.a $(UST_LIBS) $(DL_LIBS)
 
 instrumented_app_SOURCES = instrumented-app.c
 instrumented_app_LDADD = libtracepoint-trigger-example.a $(UST_LIBS) $(DL_LIBS)
 
-notification_client_SOURCES = notification-client.c
+notification_client_SOURCES = notification-client.cpp
 notification_client_LDADD = $(LIBLTTNG_CTL)
 
 endif
 notification_client_LDADD = $(LIBLTTNG_CTL)
 
 endif
diff --git a/doc/examples/trigger-condition-event-matches/notification-client.c b/doc/examples/trigger-condition-event-matches/notification-client.c
deleted file mode 100644 (file)
index 4a25155..0000000
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <lttng/lttng.h>
-
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include <common/macros.h>
-
-static int print_capture(const struct lttng_condition *condition,
-               const struct lttng_event_field_value *capture,
-               unsigned int indent_level);
-static int print_array(const struct lttng_condition *condition,
-               const struct lttng_event_field_value *array,
-               unsigned int indent_level);
-
-static void indent(unsigned int indentation_level)
-{
-       unsigned int i;
-       for (i = 0; i < indentation_level; i++) {
-               printf(" ");
-       }
-}
-
-static void print_one_event_expr(const struct lttng_event_expr *event_expr)
-{
-       enum lttng_event_expr_type type;
-
-       type = lttng_event_expr_get_type(event_expr);
-
-       switch (type) {
-       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
-       {
-               const char *name;
-
-               name = lttng_event_expr_event_payload_field_get_name(
-                               event_expr);
-               printf("%s", name);
-
-               break;
-       }
-
-       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
-       {
-               const char *name;
-
-               name = lttng_event_expr_channel_context_field_get_name(
-                               event_expr);
-               printf("$ctx.%s", name);
-
-               break;
-       }
-
-       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
-       {
-               const char *provider_name;
-               const char *type_name;
-
-               provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
-                               event_expr);
-               type_name = lttng_event_expr_app_specific_context_field_get_type_name(
-                               event_expr);
-
-               printf("$app.%s:%s", provider_name, type_name);
-
-               break;
-       }
-
-       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
-       {
-               unsigned int index;
-               const struct lttng_event_expr *parent_expr;
-               enum lttng_event_expr_status status;
-
-               parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
-                               event_expr);
-               LTTNG_ASSERT(parent_expr != NULL);
-
-               print_one_event_expr(parent_expr);
-
-               status = lttng_event_expr_array_field_element_get_index(
-                               event_expr, &index);
-               LTTNG_ASSERT(status == LTTNG_EVENT_EXPR_STATUS_OK);
-
-               printf("[%u]", index);
-
-               break;
-       }
-
-       default:
-               abort();
-       }
-}
-
-static bool action_group_contains_notify(
-               const struct lttng_action *action_group)
-{
-       unsigned int i, count;
-       enum lttng_action_status status =
-                       lttng_action_list_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_list_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 int print_capture(const struct lttng_condition *condition,
-               const struct lttng_event_field_value *capture,
-               unsigned int indent_level)
-{
-       int ret = 0;
-       enum lttng_event_field_value_status event_field_status;
-       uint64_t u_val;
-       int64_t s_val;
-       double d_val;
-       const char *string_val = NULL;
-
-       switch (lttng_event_field_value_get_type(capture)) {
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
-       {
-               event_field_status =
-                               lttng_event_field_value_unsigned_int_get_value(
-                                               capture, &u_val);
-               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       ret = 1;
-                       goto end;
-               }
-
-               printf("[Unsigned int] %" PRIu64, u_val);
-               break;
-       }
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
-       {
-               event_field_status =
-                               lttng_event_field_value_signed_int_get_value(
-                                               capture, &s_val);
-               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       ret = 1;
-                       goto end;
-               }
-
-               printf("[Signed int]  %" PRId64, s_val);
-               break;
-       }
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
-       {
-               event_field_status =
-                               lttng_event_field_value_unsigned_int_get_value(
-                                               capture, &u_val);
-               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       ret = 1;
-                       goto end;
-               }
-
-               printf("[Unsigned enum] %" PRIu64, u_val);
-               break;
-       }
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
-       {
-               event_field_status =
-                               lttng_event_field_value_signed_int_get_value(
-                                               capture, &s_val);
-               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       ret = 1;
-                       goto end;
-               }
-
-               printf("[Signed enum] %" PRId64, s_val);
-               break;
-       }
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
-       {
-               event_field_status = lttng_event_field_value_real_get_value(
-                               capture, &d_val);
-               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       ret = 1;
-                       goto end;
-               }
-
-               printf("[Real] %lf", d_val);
-               break;
-       }
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
-       {
-               event_field_status = lttng_event_field_value_string_get_value(
-                               capture, &string_val);
-               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       ret = 1;
-                       goto end;
-               }
-
-               printf("[String] %s", string_val);
-               break;
-       }
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
-               printf("[Array] [\n");
-               print_array(condition, capture, indent_level);
-               indent(indent_level);
-               printf("]\n");
-               break;
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
-       default:
-               ret = 1;
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static void print_unavailabe(void)
-{
-       printf("Capture unavailable");
-}
-
-static int print_array(const struct lttng_condition *condition,
-               const struct lttng_event_field_value *array,
-               unsigned int indent_level)
-{
-       int ret = 0;
-       enum lttng_event_field_value_status event_field_status;
-       unsigned int captured_field_count;
-
-       event_field_status = lttng_event_field_value_array_get_length(
-                       array, &captured_field_count);
-       if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               ret = 1;
-               goto end;
-       }
-
-       for (unsigned int i = 0; i < captured_field_count; i++) {
-               const struct lttng_event_field_value *captured_field = NULL;
-               const struct lttng_event_expr *expr =
-                               lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
-                                               condition, i);
-               LTTNG_ASSERT(expr);
-
-               indent(indent_level + 1);
-
-               printf("Field: ");
-               print_one_event_expr(expr);
-               printf(" Value: ");
-
-               event_field_status =
-                               lttng_event_field_value_array_get_element_at_index(
-                                               array, i, &captured_field);
-               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       if (event_field_status ==
-                                       LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
-                               print_unavailabe();
-                       } else {
-                               ret = 1;
-                               goto end;
-                       }
-               } else {
-                       print_capture(condition, captured_field,
-                                       indent_level + 1);
-               }
-
-               if (i + 1 < captured_field_count) {
-                       printf(",");
-               } else {
-                       printf(".");
-               }
-               printf("\n");
-       }
-
-end:
-       return ret;
-}
-
-static int print_captures(struct lttng_notification *notification)
-{
-       int ret = 0;
-       const struct lttng_evaluation *evaluation =
-                       lttng_notification_get_evaluation(notification);
-       const struct lttng_condition *condition =
-                       lttng_notification_get_condition(notification);
-
-       /* Status */
-       enum lttng_condition_status condition_status;
-       enum lttng_evaluation_event_rule_matches_status evaluation_status;
-
-       const struct lttng_event_field_value *captured_field_array = NULL;
-       unsigned int expected_capture_field_count;
-
-       LTTNG_ASSERT(lttng_evaluation_get_type(evaluation) ==
-                       LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES);
-
-       condition_status =
-                       lttng_condition_event_rule_matches_get_capture_descriptor_count(
-                                       condition,
-                                       &expected_capture_field_count);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               ret = 1;
-               goto end;
-       }
-
-       if (expected_capture_field_count == 0) {
-               ret = 0;
-               goto end;
-       }
-
-       evaluation_status =
-                       lttng_evaluation_event_rule_matches_get_captured_values(
-                                       evaluation, &captured_field_array);
-       if (evaluation_status != LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
-               ret = 1;
-               goto end;
-       }
-
-       printf("Captured field values:\n");
-       print_array(condition, captured_field_array, 1);
-end:
-       return ret;
-}
-
-static int print_notification(struct lttng_notification *notification)
-{
-       int ret = 0;
-       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:
-               printf("Received consumed size notification\n");
-               break;
-       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
-       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
-               printf("Received buffer usage notification\n");
-               break;
-       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
-               printf("Received session rotation ongoing notification\n");
-               break;
-       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
-               printf("Received session rotation completed notification\n");
-               break;
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
-       {
-               const char *trigger_name;
-               enum lttng_trigger_status trigger_status;
-               char time_str[64];
-               struct timeval tv;
-               time_t the_time;
-               const struct lttng_trigger *trigger = NULL;
-
-               gettimeofday(&tv, NULL);
-               the_time = tv.tv_sec;
-
-               strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
-                               localtime(&the_time));
-               printf("%s.%ld - ", time_str, tv.tv_usec);
-
-               trigger = lttng_notification_get_trigger(notification);
-               if (!trigger) {
-                       fprintf(stderr, "Failed to retrieve notification's trigger");
-                       goto end;
-               }
-
-               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-               if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-                       fprintf(stderr, "Failed to retrieve trigger's name");
-                       goto end;
-               }
-
-               printf("Received notification of event rule matches trigger \"%s\"\n",
-                               trigger_name);
-               ret = print_captures(notification);
-               break;
-       }
-       default:
-               fprintf(stderr, "Unknown notification type (%d)\n", type);
-       }
-
-end:
-       return ret;
-}
-
-int main(int argc, char **argv)
-{
-       int ret;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int count, i, j, subcription_count = 0, trigger_count;
-       enum lttng_trigger_status trigger_status;
-       struct lttng_notification_channel *notification_channel = NULL;
-
-       if (argc < 2) {
-               fprintf(stderr, "Missing trigger name(s)\n");
-               fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
-               ret = -1;
-               goto end;
-       }
-
-       trigger_count = argc - 1;
-
-       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;
-               bool subscribe = false;
-
-               lttng_trigger_get_name(trigger, &trigger_name);
-               for (j = 0; j < trigger_count; j++) {
-                       if (!strcmp(trigger_name, argv[j + 1])) {
-                               subscribe = true;
-                               break;
-                       }
-               }
-
-               if (!subscribe) {
-                       continue;
-               }
-
-               if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
-                                     action_group_contains_notify(action)) ||
-                                   action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
-                       printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
-                                       trigger_name);
-                       continue;
-               }
-
-               channel_status = lttng_notification_channel_subscribe(
-                               notification_channel, condition);
-               if (channel_status ==
-                               LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
-                       continue;
-               }
-               if (channel_status) {
-                       fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
-                                       trigger_name);
-                       ret = -1;
-                       goto end;
-               }
-
-               printf("Subscribed to notifications of trigger \"%s\"\n",
-                               trigger_name);
-               subcription_count++;
-       }
-
-       if (subcription_count == 0) {
-               printf("No matching trigger with a notify action found.\n");
-               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");
-                       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 = print_notification(notification);
-               lttng_notification_destroy(notification);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       lttng_triggers_destroy(triggers);
-       lttng_notification_channel_destroy(notification_channel);
-       return !!ret;
-}
diff --git a/doc/examples/trigger-condition-event-matches/notification-client.cpp b/doc/examples/trigger-condition-event-matches/notification-client.cpp
new file mode 100644 (file)
index 0000000..4a25155
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <lttng/lttng.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <common/macros.h>
+
+static int print_capture(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *capture,
+               unsigned int indent_level);
+static int print_array(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *array,
+               unsigned int indent_level);
+
+static void indent(unsigned int indentation_level)
+{
+       unsigned int i;
+       for (i = 0; i < indentation_level; i++) {
+               printf(" ");
+       }
+}
+
+static void print_one_event_expr(const struct lttng_event_expr *event_expr)
+{
+       enum lttng_event_expr_type type;
+
+       type = lttng_event_expr_get_type(event_expr);
+
+       switch (type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+       {
+               const char *name;
+
+               name = lttng_event_expr_event_payload_field_get_name(
+                               event_expr);
+               printf("%s", name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+       {
+               const char *name;
+
+               name = lttng_event_expr_channel_context_field_get_name(
+                               event_expr);
+               printf("$ctx.%s", name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               const char *provider_name;
+               const char *type_name;
+
+               provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
+                               event_expr);
+               type_name = lttng_event_expr_app_specific_context_field_get_type_name(
+                               event_expr);
+
+               printf("$app.%s:%s", provider_name, type_name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               unsigned int index;
+               const struct lttng_event_expr *parent_expr;
+               enum lttng_event_expr_status status;
+
+               parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
+                               event_expr);
+               LTTNG_ASSERT(parent_expr != NULL);
+
+               print_one_event_expr(parent_expr);
+
+               status = lttng_event_expr_array_field_element_get_index(
+                               event_expr, &index);
+               LTTNG_ASSERT(status == LTTNG_EVENT_EXPR_STATUS_OK);
+
+               printf("[%u]", index);
+
+               break;
+       }
+
+       default:
+               abort();
+       }
+}
+
+static bool action_group_contains_notify(
+               const struct lttng_action *action_group)
+{
+       unsigned int i, count;
+       enum lttng_action_status status =
+                       lttng_action_list_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_list_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 int print_capture(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *capture,
+               unsigned int indent_level)
+{
+       int ret = 0;
+       enum lttng_event_field_value_status event_field_status;
+       uint64_t u_val;
+       int64_t s_val;
+       double d_val;
+       const char *string_val = NULL;
+
+       switch (lttng_event_field_value_get_type(capture)) {
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
+       {
+               event_field_status =
+                               lttng_event_field_value_unsigned_int_get_value(
+                                               capture, &u_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Unsigned int] %" PRIu64, u_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
+       {
+               event_field_status =
+                               lttng_event_field_value_signed_int_get_value(
+                                               capture, &s_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Signed int]  %" PRId64, s_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+       {
+               event_field_status =
+                               lttng_event_field_value_unsigned_int_get_value(
+                                               capture, &u_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Unsigned enum] %" PRIu64, u_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+       {
+               event_field_status =
+                               lttng_event_field_value_signed_int_get_value(
+                                               capture, &s_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Signed enum] %" PRId64, s_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
+       {
+               event_field_status = lttng_event_field_value_real_get_value(
+                               capture, &d_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[Real] %lf", d_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
+       {
+               event_field_status = lttng_event_field_value_string_get_value(
+                               capture, &string_val);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       ret = 1;
+                       goto end;
+               }
+
+               printf("[String] %s", string_val);
+               break;
+       }
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
+               printf("[Array] [\n");
+               print_array(condition, capture, indent_level);
+               indent(indent_level);
+               printf("]\n");
+               break;
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
+       default:
+               ret = 1;
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static void print_unavailabe(void)
+{
+       printf("Capture unavailable");
+}
+
+static int print_array(const struct lttng_condition *condition,
+               const struct lttng_event_field_value *array,
+               unsigned int indent_level)
+{
+       int ret = 0;
+       enum lttng_event_field_value_status event_field_status;
+       unsigned int captured_field_count;
+
+       event_field_status = lttng_event_field_value_array_get_length(
+                       array, &captured_field_count);
+       if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               ret = 1;
+               goto end;
+       }
+
+       for (unsigned int i = 0; i < captured_field_count; i++) {
+               const struct lttng_event_field_value *captured_field = NULL;
+               const struct lttng_event_expr *expr =
+                               lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
+                                               condition, i);
+               LTTNG_ASSERT(expr);
+
+               indent(indent_level + 1);
+
+               printf("Field: ");
+               print_one_event_expr(expr);
+               printf(" Value: ");
+
+               event_field_status =
+                               lttng_event_field_value_array_get_element_at_index(
+                                               array, i, &captured_field);
+               if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       if (event_field_status ==
+                                       LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
+                               print_unavailabe();
+                       } else {
+                               ret = 1;
+                               goto end;
+                       }
+               } else {
+                       print_capture(condition, captured_field,
+                                       indent_level + 1);
+               }
+
+               if (i + 1 < captured_field_count) {
+                       printf(",");
+               } else {
+                       printf(".");
+               }
+               printf("\n");
+       }
+
+end:
+       return ret;
+}
+
+static int print_captures(struct lttng_notification *notification)
+{
+       int ret = 0;
+       const struct lttng_evaluation *evaluation =
+                       lttng_notification_get_evaluation(notification);
+       const struct lttng_condition *condition =
+                       lttng_notification_get_condition(notification);
+
+       /* Status */
+       enum lttng_condition_status condition_status;
+       enum lttng_evaluation_event_rule_matches_status evaluation_status;
+
+       const struct lttng_event_field_value *captured_field_array = NULL;
+       unsigned int expected_capture_field_count;
+
+       LTTNG_ASSERT(lttng_evaluation_get_type(evaluation) ==
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES);
+
+       condition_status =
+                       lttng_condition_event_rule_matches_get_capture_descriptor_count(
+                                       condition,
+                                       &expected_capture_field_count);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               ret = 1;
+               goto end;
+       }
+
+       if (expected_capture_field_count == 0) {
+               ret = 0;
+               goto end;
+       }
+
+       evaluation_status =
+                       lttng_evaluation_event_rule_matches_get_captured_values(
+                                       evaluation, &captured_field_array);
+       if (evaluation_status != LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
+               ret = 1;
+               goto end;
+       }
+
+       printf("Captured field values:\n");
+       print_array(condition, captured_field_array, 1);
+end:
+       return ret;
+}
+
+static int print_notification(struct lttng_notification *notification)
+{
+       int ret = 0;
+       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:
+               printf("Received consumed size notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+               printf("Received buffer usage notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+               printf("Received session rotation ongoing notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               printf("Received session rotation completed notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
+       {
+               const char *trigger_name;
+               enum lttng_trigger_status trigger_status;
+               char time_str[64];
+               struct timeval tv;
+               time_t the_time;
+               const struct lttng_trigger *trigger = NULL;
+
+               gettimeofday(&tv, NULL);
+               the_time = tv.tv_sec;
+
+               strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
+                               localtime(&the_time));
+               printf("%s.%ld - ", time_str, tv.tv_usec);
+
+               trigger = lttng_notification_get_trigger(notification);
+               if (!trigger) {
+                       fprintf(stderr, "Failed to retrieve notification's trigger");
+                       goto end;
+               }
+
+               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+               if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+                       fprintf(stderr, "Failed to retrieve trigger's name");
+                       goto end;
+               }
+
+               printf("Received notification of event rule matches trigger \"%s\"\n",
+                               trigger_name);
+               ret = print_captures(notification);
+               break;
+       }
+       default:
+               fprintf(stderr, "Unknown notification type (%d)\n", type);
+       }
+
+end:
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int count, i, j, subcription_count = 0, trigger_count;
+       enum lttng_trigger_status trigger_status;
+       struct lttng_notification_channel *notification_channel = NULL;
+
+       if (argc < 2) {
+               fprintf(stderr, "Missing trigger name(s)\n");
+               fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_count = argc - 1;
+
+       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;
+               bool subscribe = false;
+
+               lttng_trigger_get_name(trigger, &trigger_name);
+               for (j = 0; j < trigger_count; j++) {
+                       if (!strcmp(trigger_name, argv[j + 1])) {
+                               subscribe = true;
+                               break;
+                       }
+               }
+
+               if (!subscribe) {
+                       continue;
+               }
+
+               if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
+                                     action_group_contains_notify(action)) ||
+                                   action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
+                       printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
+                                       trigger_name);
+                       continue;
+               }
+
+               channel_status = lttng_notification_channel_subscribe(
+                               notification_channel, condition);
+               if (channel_status ==
+                               LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
+                       continue;
+               }
+               if (channel_status) {
+                       fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
+                                       trigger_name);
+                       ret = -1;
+                       goto end;
+               }
+
+               printf("Subscribed to notifications of trigger \"%s\"\n",
+                               trigger_name);
+               subcription_count++;
+       }
+
+       if (subcription_count == 0) {
+               printf("No matching trigger with a notify action found.\n");
+               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");
+                       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 = print_notification(notification);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_notification_channel_destroy(notification_channel);
+       return !!ret;
+}
index 1587deb12adfee037689cf23d5ae92a0a619d761..c67cde86d3ca3546da73dc685482e3327779a321 100644 (file)
@@ -19,7 +19,7 @@ if HAVE_LIBLTTNG_UST_CTL
 EXTRA_DIST += test_ust test_ust_tracefile_count test_lttng_ust
 endif
 
 EXTRA_DIST += test_ust test_ust_tracefile_count test_lttng_ust
 endif
 
-live_test_SOURCES = live_test.c
+live_test_SOURCES = live_test.cpp
 live_test_LDADD = $(LIBTAP) $(LIBLTTNG_SESSIOND_COMMON) $(DL_LIBS)
 
 all-local:
 live_test_LDADD = $(LIBTAP) $(LIBLTTNG_SESSIOND_COMMON) $(DL_LIBS)
 
 all-local:
diff --git a/tests/regression/tools/live/live_test.c b/tests/regression/tools/live/live_test.c
deleted file mode 100644 (file)
index 40d0f62..0000000
+++ /dev/null
@@ -1,729 +0,0 @@
-/*
- * Copyright (C) 2013 Julien Desfossez <jdesfossez@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <common/compat/time.h>
-#include <sys/types.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <tap/tap.h>
-#include <lttng/lttng.h>
-
-#include <urcu/list.h>
-#include <common/common.h>
-
-#include <bin/lttng-relayd/lttng-viewer-abi.h>
-#include <common/index/ctf-index.h>
-
-#include <common/compat/errno.h>
-#include <common/compat/endian.h>
-
-#define SESSION1 "test1"
-#define RELAYD_URL "net://localhost"
-#define LIVE_TIMER 2000000
-
-/* Number of TAP tests in this file */
-#define NUM_TESTS 11
-#define mmap_size 524288
-
-#ifdef HAVE_LIBLTTNG_UST_CTL
-#include <lttng/lttng-export.h>
-#include <lttng/ust-sigbus.h>
-LTTNG_EXPORT DEFINE_LTTNG_UST_SIGBUS_STATE();
-#endif
-
-static int control_sock;
-struct live_session *session;
-
-static int first_packet_offset;
-static int first_packet_len;
-static int first_packet_stream_id = -1;
-
-struct viewer_stream {
-       uint64_t id;
-       uint64_t ctf_trace_id;
-       void *mmap_base;
-       int fd;
-       int metadata_flag;
-       int first_read;
-       char path[PATH_MAX];
-};
-
-struct live_session {
-       struct viewer_stream *streams;
-       uint64_t live_timer_interval;
-       uint64_t stream_count;
-};
-
-static
-ssize_t lttng_live_recv(int fd, void *buf, size_t len)
-{
-       ssize_t ret;
-       size_t copied = 0, to_copy = len;
-
-       do {
-               ret = recv(fd, buf + copied, to_copy, 0);
-               if (ret > 0) {
-                       LTTNG_ASSERT(ret <= to_copy);
-                       copied += ret;
-                       to_copy -= ret;
-               }
-       } while ((ret > 0 && to_copy > 0)
-               || (ret < 0 && errno == EINTR));
-       if (ret > 0)
-               ret = copied;
-       /* ret = 0 means orderly shutdown, ret < 0 is error. */
-       return ret;
-}
-
-static
-ssize_t lttng_live_send(int fd, const void *buf, size_t len)
-{
-       ssize_t ret;
-
-       do {
-               ret = send(fd, buf, len, MSG_NOSIGNAL);
-       } while (ret < 0 && errno == EINTR);
-       return ret;
-}
-
-static
-int connect_viewer(const char *hostname)
-{
-       struct hostent *host;
-       struct sockaddr_in server_addr;
-       int ret;
-
-       host = gethostbyname(hostname);
-       if (!host) {
-               ret = -1;
-               goto end;
-       }
-
-       if ((control_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
-               PERROR("Socket");
-               ret = -1;
-               goto end;
-       }
-
-       server_addr.sin_family = AF_INET;
-       server_addr.sin_port = htons(5344);
-       server_addr.sin_addr = *((struct in_addr *) host->h_addr);
-       bzero(&(server_addr.sin_zero), 8);
-
-       if (connect(control_sock, (struct sockaddr *) &server_addr,
-                               sizeof(struct sockaddr)) == -1) {
-               PERROR("Connect");
-               ret = -1;
-               goto end;
-       }
-
-       server_addr.sin_family = AF_INET;
-       server_addr.sin_port = htons(5345);
-       server_addr.sin_addr = *((struct in_addr *) host->h_addr);
-       bzero(&(server_addr.sin_zero), 8);
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int establish_connection(void)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_connect connect;
-       ssize_t ret_len;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT);
-       cmd.data_size = htobe64(sizeof(connect));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&connect, 0, sizeof(connect));
-       connect.major = htobe32(VERSION_MAJOR);
-       connect.minor = htobe32(VERSION_MINOR);
-       connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND);
-
-       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-       if (ret_len < 0) {
-               diag("Error sending cmd");
-               goto error;
-       }
-       ret_len = lttng_live_send(control_sock, &connect, sizeof(connect));
-       if (ret_len < 0) {
-               diag("Error sending version");
-               goto error;
-       }
-
-       ret_len = lttng_live_recv(control_sock, &connect, sizeof(connect));
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len < 0) {
-               diag("Error receiving version");
-               goto error;
-       }
-       return 0;
-
-error:
-       return -1;
-}
-
-/*
- * Returns the number of sessions, should be 1 during the unit test.
- */
-static
-int list_sessions(uint64_t *session_id)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_list_sessions list;
-       struct lttng_viewer_session lsession;
-       int i;
-       ssize_t ret_len;
-       int first_session = 0;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
-       cmd.data_size = htobe64(0);
-       cmd.cmd_version = htobe32(0);
-
-       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-       if (ret_len < 0) {
-               diag("Error sending cmd");
-               goto error;
-       }
-
-       ret_len = lttng_live_recv(control_sock, &list, sizeof(list));
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len < 0) {
-               diag("Error receiving session list");
-               goto error;
-       }
-
-       for (i = 0; i < be32toh(list.sessions_count); i++) {
-               ret_len = lttng_live_recv(control_sock, &lsession, sizeof(lsession));
-               if (ret_len < 0) {
-                       diag("Error receiving session");
-                       goto error;
-               }
-               if (lsession.streams > 0 && first_session <= 0) {
-                       first_session = be64toh(lsession.id);
-                       *session_id = first_session;
-               }
-       }
-
-       return be32toh(list.sessions_count);
-
-error:
-       return -1;
-}
-
-static
-int create_viewer_session(void)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_create_session_response resp;
-       ssize_t ret_len;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION);
-       cmd.data_size = htobe64(0);
-       cmd.cmd_version = htobe32(0);
-
-       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-       if (ret_len < 0) {
-               diag("[error] Error sending cmd");
-               goto error;
-       }
-       LTTNG_ASSERT(ret_len == sizeof(cmd));
-
-       ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len < 0) {
-               diag("[error] Error receiving create session reply");
-               goto error;
-       }
-       LTTNG_ASSERT(ret_len == sizeof(resp));
-
-       if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) {
-               diag("[error] Error creating viewer session");
-               goto error;
-       }
-       return 0;
-
-error:
-       return -1;
-}
-
-static
-int attach_session(uint64_t id)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_attach_session_request rq;
-       struct lttng_viewer_attach_session_response rp;
-       struct lttng_viewer_stream stream;
-       int i;
-       ssize_t ret_len;
-
-       session = zmalloc(sizeof(struct live_session));
-       if (!session) {
-               goto error;
-       }
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION);
-       cmd.data_size = htobe64(sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.session_id = htobe64(id);
-       rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING);
-
-       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-       if (ret_len < 0) {
-               diag("Error sending cmd LTTNG_VIEWER_ATTACH_SESSION");
-               goto error;
-       }
-       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
-       if (ret_len < 0) {
-               diag("Error sending attach request");
-               goto error;
-       }
-
-       ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len < 0) {
-               diag("Error receiving attach response");
-               goto error;
-       }
-       if (be32toh(rp.status) != LTTNG_VIEWER_ATTACH_OK) {
-               goto error;
-       }
-
-       session->stream_count = be32toh(rp.streams_count);
-       if (session->stream_count == 0) {
-               diag("Got session stream count == 0");
-               goto error;
-       }
-       session->streams = zmalloc(session->stream_count *
-                       sizeof(struct viewer_stream));
-       if (!session->streams) {
-               goto error;
-       }
-
-       for (i = 0; i < be32toh(rp.streams_count); i++) {
-               ret_len = lttng_live_recv(control_sock, &stream, sizeof(stream));
-               if (ret_len == 0) {
-                       diag("[error] Remote side has closed connection");
-                       goto error;
-               }
-               if (ret_len < 0) {
-                       diag("Error receiving stream");
-                       goto error;
-               }
-               session->streams[i].id = be64toh(stream.id);
-
-               session->streams[i].ctf_trace_id = be64toh(stream.ctf_trace_id);
-               session->streams[i].first_read = 1;
-               session->streams[i].mmap_base = mmap(NULL, mmap_size,
-                               PROT_READ | PROT_WRITE,
-                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-               if (session->streams[i].mmap_base == MAP_FAILED) {
-                       diag("mmap error");
-                       goto error;
-               }
-
-               if (be32toh(stream.metadata_flag)) {
-                       session->streams[i].metadata_flag = 1;
-               }
-       }
-       return session->stream_count;
-
-error:
-       return -1;
-}
-
-static
-int get_metadata(void)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_get_metadata rq;
-       struct lttng_viewer_metadata_packet rp;
-       ssize_t ret_len;
-       int ret;
-       uint64_t i;
-       char *data = NULL;
-       uint64_t len = 0;
-       int metadata_stream_id = -1;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA);
-       cmd.data_size = htobe64(sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       for (i = 0; i < session->stream_count; i++) {
-               if (session->streams[i].metadata_flag) {
-                       metadata_stream_id = i;
-                       break;
-               }
-       }
-
-       if (metadata_stream_id < 0) {
-               diag("No metadata stream found");
-               goto error;
-       }
-
-       rq.stream_id = htobe64(session->streams[metadata_stream_id].id);
-
-retry:
-       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-       if (ret_len < 0) {
-               diag("Error sending cmd");
-               goto error;
-       }
-       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
-       if (ret_len < 0) {
-               diag("Error sending get_metadata request");
-               goto error;
-       }
-       ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len < 0) {
-               diag("Error receiving metadata response");
-               goto error;
-       }
-       switch (be32toh(rp.status)) {
-       case LTTNG_VIEWER_METADATA_OK:
-               break;
-       case LTTNG_VIEWER_NO_NEW_METADATA:
-               diag("Got LTTNG_VIEWER_NO_NEW_METADATA:");
-               usleep(50);
-               goto retry;
-       case LTTNG_VIEWER_METADATA_ERR:
-               diag("Got LTTNG_VIEWER_METADATA_ERR:");
-               goto error;
-       default:
-               diag("Got unknown status during LTTNG_VIEWER_GET_METADATA");
-               goto error;
-       }
-
-       len = be64toh(rp.len);
-       if (len <= 0) {
-               goto error;
-       }
-
-       data = zmalloc(len);
-       if (!data) {
-               PERROR("relay data zmalloc");
-               goto error;
-       }
-       ret_len = lttng_live_recv(control_sock, data, len);
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error_free_data;
-       }
-       if (ret_len < 0) {
-               diag("Error receiving trace packet");
-               goto error_free_data;
-       }
-       free(data);
-       ret = len;
-
-       return ret;
-
-error_free_data:
-       free(data);
-error:
-       return -1;
-}
-
-static
-int get_next_index(void)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_get_next_index rq;
-       struct lttng_viewer_index rp;
-       ssize_t ret_len;
-       int id;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
-       cmd.data_size = htobe64(sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       for (id = 0; id < session->stream_count; id++) {
-               if (session->streams[id].metadata_flag) {
-                       continue;
-               }
-               memset(&rq, 0, sizeof(rq));
-               rq.stream_id = htobe64(session->streams[id].id);
-
-retry:
-               ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-               if (ret_len < 0) {
-                       diag("Error sending cmd");
-                       goto error;
-               }
-               ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
-               if (ret_len < 0) {
-                       diag("Error sending get_next_index request");
-                       goto error;
-               }
-               ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
-               if (ret_len == 0) {
-                       diag("[error] Remote side has closed connection");
-                       goto error;
-               }
-               if (ret_len < 0) {
-                       diag("Error receiving index response");
-                       goto error;
-               }
-
-               rp.flags = be32toh(rp.flags);
-
-               switch (be32toh(rp.status)) {
-               case LTTNG_VIEWER_INDEX_INACTIVE:
-                       /* Skip this stream. */
-                       diag("Got LTTNG_VIEWER_INDEX_INACTIVE");
-                       continue;
-               case LTTNG_VIEWER_INDEX_OK:
-                       break;
-               case LTTNG_VIEWER_INDEX_RETRY:
-                       sleep(1);
-                       goto retry;
-               case LTTNG_VIEWER_INDEX_HUP:
-                       diag("Got LTTNG_VIEWER_INDEX_HUP");
-                       session->streams[id].id = -1ULL;
-                       session->streams[id].fd = -1;
-                       goto error;
-               case LTTNG_VIEWER_INDEX_ERR:
-                       diag("Got LTTNG_VIEWER_INDEX_ERR");
-                       goto error;
-               default:
-                       diag("Unknown reply status during LTTNG_VIEWER_GET_NEXT_INDEX (%d)", be32toh(rp.status));
-                       goto error;
-               }
-               if (first_packet_stream_id < 0) {
-                       /*
-                        * Initialize the first packet stream id. That is,
-                        * the first active stream encoutered.
-                        */
-                       first_packet_offset = be64toh(rp.offset);
-                       first_packet_len = be64toh(rp.packet_size) / CHAR_BIT;
-                       first_packet_stream_id = id;
-                       diag("Got first packet index with offset %d and len %d",
-                                       first_packet_offset, first_packet_len);
-               }
-       }
-       return 0;
-
-error:
-       return -1;
-}
-
-static
-int get_data_packet(int id, uint64_t offset,
-               uint64_t len)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_get_packet rq;
-       struct lttng_viewer_trace_packet rp;
-       ssize_t ret_len;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET);
-       cmd.data_size = htobe64(sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.stream_id = htobe64(session->streams[id].id);
-       /* Already in big endian. */
-       rq.offset = offset;
-       rq.len = htobe32(len);
-
-       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-       if (ret_len < 0) {
-               diag("Error sending cmd");
-               goto error;
-       }
-       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
-       if (ret_len < 0) {
-               diag("Error sending get_data_packet request");
-               goto error;
-       }
-       ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len < 0) {
-               diag("Error receiving data response");
-               goto error;
-       }
-       rp.flags = be32toh(rp.flags);
-
-       switch (be32toh(rp.status)) {
-       case LTTNG_VIEWER_GET_PACKET_OK:
-               len = be32toh(rp.len);
-               if (len == 0) {
-                       diag("Got LTTNG_VIEWER_GET_PACKET_OK, but len == 0");
-                       goto error;
-               }
-               break;
-       case LTTNG_VIEWER_GET_PACKET_RETRY:
-               diag("Got LTTNG_VIEWER_GET_PACKET_RETRY:");
-               goto error;
-       case LTTNG_VIEWER_GET_PACKET_ERR:
-               if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
-                       diag("Got LTTNG_VIEWER_GET_PACKET_ERR with NEW_METADATA flag");
-                       goto end;
-               }
-               diag("Got LTTNG_VIEWER_GET_PACKET_ERR:");
-               goto error;
-       default:
-               diag("Got unknown status code during LTTNG_VIEWER_GET_PACKET");
-               goto error;
-       }
-
-       if (len > mmap_size) {
-               diag("mmap_size not big enough");
-               goto error;
-       }
-
-       ret_len = lttng_live_recv(control_sock, session->streams[id].mmap_base, len);
-       if (ret_len == 0) {
-               diag("[error] Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len < 0) {
-               diag("Error receiving trace packet");
-               goto error;
-       }
-end:
-       return 0;
-error:
-       return -1;
-}
-
-static
-int detach_viewer_session(uint64_t id)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_detach_session_response resp;
-       struct lttng_viewer_detach_session_request rq;
-       int ret;
-       ssize_t ret_len;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION);
-       cmd.data_size = htobe64(sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.session_id = htobe64(id);
-
-       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
-       if (ret_len < 0) {
-               fprintf(stderr, "[error] Error sending cmd\n");
-               ret = ret_len;
-               goto error;
-       }
-
-       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
-       if (ret_len < 0) {
-               fprintf(stderr, "Error sending attach request\n");
-               ret = ret_len;
-               goto error;
-       }
-
-       ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
-       if (ret_len < 0) {
-               fprintf(stderr, "[error] Error receiving detach session reply\n");
-               ret = ret_len;
-               goto error;
-       }
-
-       if (be32toh(resp.status) != LTTNG_VIEWER_DETACH_SESSION_OK) {
-               fprintf(stderr, "[error] Error detaching viewer session\n");
-               ret = -1;
-               goto error;
-       }
-       ret = 0;
-
-error:
-       return ret;
-}
-
-int main(int argc, char **argv)
-{
-       int ret;
-       uint64_t session_id;
-
-       plan_tests(NUM_TESTS);
-
-       diag("Live unit tests");
-
-       ret = connect_viewer("localhost");
-       ok(ret == 0, "Connect viewer to relayd");
-
-       ret = establish_connection();
-       ok(ret == 0, "Established connection and version check with %d.%d",
-                       VERSION_MAJOR, VERSION_MINOR);
-
-       ret = list_sessions(&session_id);
-       ok(ret > 0, "List sessions : %d session(s)", ret);
-       if (ret < 0) {
-               goto end;
-       }
-
-       ret = create_viewer_session();
-       ok(ret == 0, "Create viewer session");
-
-       ret = attach_session(session_id);
-       ok(ret > 0, "Attach to session, %d stream(s) received", ret);
-
-       ret = get_metadata();
-       ok(ret > 0, "Get metadata, received %d bytes", ret);
-
-       ret = get_next_index();
-       ok(ret == 0, "Get one index per stream");
-
-       ret = get_data_packet(first_packet_stream_id, first_packet_offset,
-                       first_packet_len);
-       ok(ret == 0,
-                       "Get one data packet for stream %d, offset %d, len %d",
-                       first_packet_stream_id, first_packet_offset,
-                       first_packet_len);
-
-       ret = detach_viewer_session(session_id);
-       ok(ret == 0, "Detach viewer session");
-
-       ret = list_sessions(&session_id);
-       ok(ret > 0, "List sessions : %d session(s)", ret);
-
-       ret = attach_session(session_id);
-       ok(ret > 0, "Attach to session, %d streams received", ret);
-end:
-       return exit_status();
-}
diff --git a/tests/regression/tools/live/live_test.cpp b/tests/regression/tools/live/live_test.cpp
new file mode 100644 (file)
index 0000000..afaf23b
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * Copyright (C) 2013 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <common/compat/time.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <tap/tap.h>
+#include <lttng/lttng.h>
+
+#include <urcu/list.h>
+#include <common/common.h>
+
+#include <bin/lttng-relayd/lttng-viewer-abi.h>
+#include <common/index/ctf-index.h>
+
+#include <common/compat/errno.h>
+#include <common/compat/endian.h>
+
+#define SESSION1 "test1"
+#define RELAYD_URL "net://localhost"
+#define LIVE_TIMER 2000000
+
+/* Number of TAP tests in this file */
+#define NUM_TESTS 11
+#define mmap_size 524288
+
+#ifdef HAVE_LIBLTTNG_UST_CTL
+#include <lttng/lttng-export.h>
+#include <lttng/ust-sigbus.h>
+LTTNG_EXPORT DEFINE_LTTNG_UST_SIGBUS_STATE();
+#endif
+
+static int control_sock;
+struct live_session *session;
+
+static int first_packet_offset;
+static int first_packet_len;
+static int first_packet_stream_id = -1;
+
+struct viewer_stream {
+       uint64_t id;
+       uint64_t ctf_trace_id;
+       void *mmap_base;
+       int fd;
+       int metadata_flag;
+       int first_read;
+       char path[PATH_MAX];
+};
+
+struct live_session {
+       struct viewer_stream *streams;
+       uint64_t live_timer_interval;
+       uint64_t stream_count;
+};
+
+static
+ssize_t lttng_live_recv(int fd, void *buf, size_t len)
+{
+       ssize_t ret;
+       size_t copied = 0, to_copy = len;
+
+       do {
+               ret = recv(fd, (char *) buf + copied, to_copy, 0);
+               if (ret > 0) {
+                       LTTNG_ASSERT(ret <= to_copy);
+                       copied += ret;
+                       to_copy -= ret;
+               }
+       } while ((ret > 0 && to_copy > 0)
+               || (ret < 0 && errno == EINTR));
+       if (ret > 0)
+               ret = copied;
+       /* ret = 0 means orderly shutdown, ret < 0 is error. */
+       return ret;
+}
+
+static
+ssize_t lttng_live_send(int fd, const void *buf, size_t len)
+{
+       ssize_t ret;
+
+       do {
+               ret = send(fd, buf, len, MSG_NOSIGNAL);
+       } while (ret < 0 && errno == EINTR);
+       return ret;
+}
+
+static
+int connect_viewer(const char *hostname)
+{
+       struct hostent *host;
+       struct sockaddr_in server_addr;
+       int ret;
+
+       host = gethostbyname(hostname);
+       if (!host) {
+               ret = -1;
+               goto end;
+       }
+
+       if ((control_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+               PERROR("Socket");
+               ret = -1;
+               goto end;
+       }
+
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_port = htons(5344);
+       server_addr.sin_addr = *((struct in_addr *) host->h_addr);
+       bzero(&(server_addr.sin_zero), 8);
+
+       if (connect(control_sock, (struct sockaddr *) &server_addr,
+                               sizeof(struct sockaddr)) == -1) {
+               PERROR("Connect");
+               ret = -1;
+               goto end;
+       }
+
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_port = htons(5345);
+       server_addr.sin_addr = *((struct in_addr *) host->h_addr);
+       bzero(&(server_addr.sin_zero), 8);
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static
+int establish_connection(void)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_connect connect;
+       ssize_t ret_len;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT);
+       cmd.data_size = htobe64(sizeof(connect));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&connect, 0, sizeof(connect));
+       connect.major = htobe32(VERSION_MAJOR);
+       connect.minor = htobe32(VERSION_MINOR);
+       connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND);
+
+       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+       if (ret_len < 0) {
+               diag("Error sending cmd");
+               goto error;
+       }
+       ret_len = lttng_live_send(control_sock, &connect, sizeof(connect));
+       if (ret_len < 0) {
+               diag("Error sending version");
+               goto error;
+       }
+
+       ret_len = lttng_live_recv(control_sock, &connect, sizeof(connect));
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len < 0) {
+               diag("Error receiving version");
+               goto error;
+       }
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ * Returns the number of sessions, should be 1 during the unit test.
+ */
+static
+int list_sessions(uint64_t *session_id)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_list_sessions list;
+       struct lttng_viewer_session lsession;
+       int i;
+       ssize_t ret_len;
+       int first_session = 0;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
+       cmd.data_size = htobe64(0);
+       cmd.cmd_version = htobe32(0);
+
+       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+       if (ret_len < 0) {
+               diag("Error sending cmd");
+               goto error;
+       }
+
+       ret_len = lttng_live_recv(control_sock, &list, sizeof(list));
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len < 0) {
+               diag("Error receiving session list");
+               goto error;
+       }
+
+       for (i = 0; i < be32toh(list.sessions_count); i++) {
+               ret_len = lttng_live_recv(control_sock, &lsession, sizeof(lsession));
+               if (ret_len < 0) {
+                       diag("Error receiving session");
+                       goto error;
+               }
+               if (lsession.streams > 0 && first_session <= 0) {
+                       first_session = be64toh(lsession.id);
+                       *session_id = first_session;
+               }
+       }
+
+       return be32toh(list.sessions_count);
+
+error:
+       return -1;
+}
+
+static
+int create_viewer_session(void)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_create_session_response resp;
+       ssize_t ret_len;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION);
+       cmd.data_size = htobe64(0);
+       cmd.cmd_version = htobe32(0);
+
+       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+       if (ret_len < 0) {
+               diag("[error] Error sending cmd");
+               goto error;
+       }
+       LTTNG_ASSERT(ret_len == sizeof(cmd));
+
+       ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len < 0) {
+               diag("[error] Error receiving create session reply");
+               goto error;
+       }
+       LTTNG_ASSERT(ret_len == sizeof(resp));
+
+       if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) {
+               diag("[error] Error creating viewer session");
+               goto error;
+       }
+       return 0;
+
+error:
+       return -1;
+}
+
+static
+int attach_session(uint64_t id)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_attach_session_request rq;
+       struct lttng_viewer_attach_session_response rp;
+       struct lttng_viewer_stream stream;
+       int i;
+       ssize_t ret_len;
+
+       session = (live_session *) zmalloc(sizeof(struct live_session));
+       if (!session) {
+               goto error;
+       }
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION);
+       cmd.data_size = htobe64(sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.session_id = htobe64(id);
+       rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING);
+
+       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+       if (ret_len < 0) {
+               diag("Error sending cmd LTTNG_VIEWER_ATTACH_SESSION");
+               goto error;
+       }
+       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+       if (ret_len < 0) {
+               diag("Error sending attach request");
+               goto error;
+       }
+
+       ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len < 0) {
+               diag("Error receiving attach response");
+               goto error;
+       }
+       if (be32toh(rp.status) != LTTNG_VIEWER_ATTACH_OK) {
+               goto error;
+       }
+
+       session->stream_count = be32toh(rp.streams_count);
+       if (session->stream_count == 0) {
+               diag("Got session stream count == 0");
+               goto error;
+       }
+       session->streams = (viewer_stream *) zmalloc(session->stream_count *
+                       sizeof(struct viewer_stream));
+       if (!session->streams) {
+               goto error;
+       }
+
+       for (i = 0; i < be32toh(rp.streams_count); i++) {
+               ret_len = lttng_live_recv(control_sock, &stream, sizeof(stream));
+               if (ret_len == 0) {
+                       diag("[error] Remote side has closed connection");
+                       goto error;
+               }
+               if (ret_len < 0) {
+                       diag("Error receiving stream");
+                       goto error;
+               }
+               session->streams[i].id = be64toh(stream.id);
+
+               session->streams[i].ctf_trace_id = be64toh(stream.ctf_trace_id);
+               session->streams[i].first_read = 1;
+               session->streams[i].mmap_base = mmap(NULL, mmap_size,
+                               PROT_READ | PROT_WRITE,
+                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+               if (session->streams[i].mmap_base == MAP_FAILED) {
+                       diag("mmap error");
+                       goto error;
+               }
+
+               if (be32toh(stream.metadata_flag)) {
+                       session->streams[i].metadata_flag = 1;
+               }
+       }
+       return session->stream_count;
+
+error:
+       return -1;
+}
+
+static
+int get_metadata(void)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_get_metadata rq;
+       struct lttng_viewer_metadata_packet rp;
+       ssize_t ret_len;
+       int ret;
+       uint64_t i;
+       char *data = NULL;
+       uint64_t len = 0;
+       int metadata_stream_id = -1;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA);
+       cmd.data_size = htobe64(sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       for (i = 0; i < session->stream_count; i++) {
+               if (session->streams[i].metadata_flag) {
+                       metadata_stream_id = i;
+                       break;
+               }
+       }
+
+       if (metadata_stream_id < 0) {
+               diag("No metadata stream found");
+               goto error;
+       }
+
+       rq.stream_id = htobe64(session->streams[metadata_stream_id].id);
+
+retry:
+       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+       if (ret_len < 0) {
+               diag("Error sending cmd");
+               goto error;
+       }
+       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+       if (ret_len < 0) {
+               diag("Error sending get_metadata request");
+               goto error;
+       }
+       ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len < 0) {
+               diag("Error receiving metadata response");
+               goto error;
+       }
+       switch (be32toh(rp.status)) {
+       case LTTNG_VIEWER_METADATA_OK:
+               break;
+       case LTTNG_VIEWER_NO_NEW_METADATA:
+               diag("Got LTTNG_VIEWER_NO_NEW_METADATA:");
+               usleep(50);
+               goto retry;
+       case LTTNG_VIEWER_METADATA_ERR:
+               diag("Got LTTNG_VIEWER_METADATA_ERR:");
+               goto error;
+       default:
+               diag("Got unknown status during LTTNG_VIEWER_GET_METADATA");
+               goto error;
+       }
+
+       len = be64toh(rp.len);
+       if (len <= 0) {
+               goto error;
+       }
+
+       data = (char *) zmalloc(len);
+       if (!data) {
+               PERROR("relay data zmalloc");
+               goto error;
+       }
+       ret_len = lttng_live_recv(control_sock, data, len);
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error_free_data;
+       }
+       if (ret_len < 0) {
+               diag("Error receiving trace packet");
+               goto error_free_data;
+       }
+       free(data);
+       ret = len;
+
+       return ret;
+
+error_free_data:
+       free(data);
+error:
+       return -1;
+}
+
+static
+int get_next_index(void)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_get_next_index rq;
+       struct lttng_viewer_index rp;
+       ssize_t ret_len;
+       int id;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
+       cmd.data_size = htobe64(sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       for (id = 0; id < session->stream_count; id++) {
+               if (session->streams[id].metadata_flag) {
+                       continue;
+               }
+               memset(&rq, 0, sizeof(rq));
+               rq.stream_id = htobe64(session->streams[id].id);
+
+retry:
+               ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+               if (ret_len < 0) {
+                       diag("Error sending cmd");
+                       goto error;
+               }
+               ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+               if (ret_len < 0) {
+                       diag("Error sending get_next_index request");
+                       goto error;
+               }
+               ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+               if (ret_len == 0) {
+                       diag("[error] Remote side has closed connection");
+                       goto error;
+               }
+               if (ret_len < 0) {
+                       diag("Error receiving index response");
+                       goto error;
+               }
+
+               rp.flags = be32toh(rp.flags);
+
+               switch (be32toh(rp.status)) {
+               case LTTNG_VIEWER_INDEX_INACTIVE:
+                       /* Skip this stream. */
+                       diag("Got LTTNG_VIEWER_INDEX_INACTIVE");
+                       continue;
+               case LTTNG_VIEWER_INDEX_OK:
+                       break;
+               case LTTNG_VIEWER_INDEX_RETRY:
+                       sleep(1);
+                       goto retry;
+               case LTTNG_VIEWER_INDEX_HUP:
+                       diag("Got LTTNG_VIEWER_INDEX_HUP");
+                       session->streams[id].id = -1ULL;
+                       session->streams[id].fd = -1;
+                       goto error;
+               case LTTNG_VIEWER_INDEX_ERR:
+                       diag("Got LTTNG_VIEWER_INDEX_ERR");
+                       goto error;
+               default:
+                       diag("Unknown reply status during LTTNG_VIEWER_GET_NEXT_INDEX (%d)", be32toh(rp.status));
+                       goto error;
+               }
+               if (first_packet_stream_id < 0) {
+                       /*
+                        * Initialize the first packet stream id. That is,
+                        * the first active stream encoutered.
+                        */
+                       first_packet_offset = be64toh(rp.offset);
+                       first_packet_len = be64toh(rp.packet_size) / CHAR_BIT;
+                       first_packet_stream_id = id;
+                       diag("Got first packet index with offset %d and len %d",
+                                       first_packet_offset, first_packet_len);
+               }
+       }
+       return 0;
+
+error:
+       return -1;
+}
+
+static
+int get_data_packet(int id, uint64_t offset,
+               uint64_t len)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_get_packet rq;
+       struct lttng_viewer_trace_packet rp;
+       ssize_t ret_len;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET);
+       cmd.data_size = htobe64(sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.stream_id = htobe64(session->streams[id].id);
+       /* Already in big endian. */
+       rq.offset = offset;
+       rq.len = htobe32(len);
+
+       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+       if (ret_len < 0) {
+               diag("Error sending cmd");
+               goto error;
+       }
+       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+       if (ret_len < 0) {
+               diag("Error sending get_data_packet request");
+               goto error;
+       }
+       ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len < 0) {
+               diag("Error receiving data response");
+               goto error;
+       }
+       rp.flags = be32toh(rp.flags);
+
+       switch (be32toh(rp.status)) {
+       case LTTNG_VIEWER_GET_PACKET_OK:
+               len = be32toh(rp.len);
+               if (len == 0) {
+                       diag("Got LTTNG_VIEWER_GET_PACKET_OK, but len == 0");
+                       goto error;
+               }
+               break;
+       case LTTNG_VIEWER_GET_PACKET_RETRY:
+               diag("Got LTTNG_VIEWER_GET_PACKET_RETRY:");
+               goto error;
+       case LTTNG_VIEWER_GET_PACKET_ERR:
+               if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
+                       diag("Got LTTNG_VIEWER_GET_PACKET_ERR with NEW_METADATA flag");
+                       goto end;
+               }
+               diag("Got LTTNG_VIEWER_GET_PACKET_ERR:");
+               goto error;
+       default:
+               diag("Got unknown status code during LTTNG_VIEWER_GET_PACKET");
+               goto error;
+       }
+
+       if (len > mmap_size) {
+               diag("mmap_size not big enough");
+               goto error;
+       }
+
+       ret_len = lttng_live_recv(control_sock, session->streams[id].mmap_base, len);
+       if (ret_len == 0) {
+               diag("[error] Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len < 0) {
+               diag("Error receiving trace packet");
+               goto error;
+       }
+end:
+       return 0;
+error:
+       return -1;
+}
+
+static
+int detach_viewer_session(uint64_t id)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_detach_session_response resp;
+       struct lttng_viewer_detach_session_request rq;
+       int ret;
+       ssize_t ret_len;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION);
+       cmd.data_size = htobe64(sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.session_id = htobe64(id);
+
+       ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+       if (ret_len < 0) {
+               fprintf(stderr, "[error] Error sending cmd\n");
+               ret = ret_len;
+               goto error;
+       }
+
+       ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+       if (ret_len < 0) {
+               fprintf(stderr, "Error sending attach request\n");
+               ret = ret_len;
+               goto error;
+       }
+
+       ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
+       if (ret_len < 0) {
+               fprintf(stderr, "[error] Error receiving detach session reply\n");
+               ret = ret_len;
+               goto error;
+       }
+
+       if (be32toh(resp.status) != LTTNG_VIEWER_DETACH_SESSION_OK) {
+               fprintf(stderr, "[error] Error detaching viewer session\n");
+               ret = -1;
+               goto error;
+       }
+       ret = 0;
+
+error:
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       uint64_t session_id;
+
+       plan_tests(NUM_TESTS);
+
+       diag("Live unit tests");
+
+       ret = connect_viewer("localhost");
+       ok(ret == 0, "Connect viewer to relayd");
+
+       ret = establish_connection();
+       ok(ret == 0, "Established connection and version check with %d.%d",
+                       VERSION_MAJOR, VERSION_MINOR);
+
+       ret = list_sessions(&session_id);
+       ok(ret > 0, "List sessions : %d session(s)", ret);
+       if (ret < 0) {
+               goto end;
+       }
+
+       ret = create_viewer_session();
+       ok(ret == 0, "Create viewer session");
+
+       ret = attach_session(session_id);
+       ok(ret > 0, "Attach to session, %d stream(s) received", ret);
+
+       ret = get_metadata();
+       ok(ret > 0, "Get metadata, received %d bytes", ret);
+
+       ret = get_next_index();
+       ok(ret == 0, "Get one index per stream");
+
+       ret = get_data_packet(first_packet_stream_id, first_packet_offset,
+                       first_packet_len);
+       ok(ret == 0,
+                       "Get one data packet for stream %d, offset %d, len %d",
+                       first_packet_stream_id, first_packet_offset,
+                       first_packet_len);
+
+       ret = detach_viewer_session(session_id);
+       ok(ret == 0, "Detach viewer session");
+
+       ret = list_sessions(&session_id);
+       ok(ret > 0, "List sessions : %d session(s)", ret);
+
+       ret = attach_session(session_id);
+       ok(ret > 0, "Attach to session, %d streams received", ret);
+end:
+       return exit_status();
+}
index 2f1a9174e9a867cb7f9cbcf712e0b5144120c062..4029a21263d640dd572d130113c08aaea63192fd 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 # SPDX-License-Identifier: GPL-2.0-only
 
-AM_CFLAGS += -I$(top_srcdir)/tests/utils
+AM_CPPFLAGS += -I$(top_srcdir)/tests/utils
 
 LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 LIB_LTTNG_CTL = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
 LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 LIB_LTTNG_CTL = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
@@ -14,7 +14,7 @@ EXTRA_DIST = \
             base_client.c \
             consumer_testpoints.cpp \
             sessiond_testpoints.cpp \
             base_client.c \
             consumer_testpoints.cpp \
             sessiond_testpoints.cpp \
-            notification.c \
+            notification.cpp \
             test_notification_kernel_buffer_usage \
             test_notification_kernel_capture \
             test_notification_kernel_error \
             test_notification_kernel_buffer_usage \
             test_notification_kernel_capture \
             test_notification_kernel_error \
@@ -54,9 +54,9 @@ noinst_LTLIBRARIES = libpause_sessiond.la libpause_consumer.la
 base_client_SOURCES = base_client.c
 base_client_LDADD = $(LIB_LTTNG_CTL)
 
 base_client_SOURCES = base_client.c
 base_client_LDADD = $(LIB_LTTNG_CTL)
 
-notification_SOURCES = notification.c
+notification_SOURCES = notification.cpp
 # Tests the deprecated lttng_register_trigger() interface
 # Tests the deprecated lttng_register_trigger() interface
-notification_CFLAGS = -Wno-deprecated-declarations $(AM_CFLAGS)
+notification_CXXFLAGS = -Wno-deprecated-declarations $(AM_CXXFLAGS)
 notification_LDADD = $(LIB_LTTNG_CTL) $(LIBTAP) -lm
 
 rotation_SOURCES = rotation.c
 notification_LDADD = $(LIB_LTTNG_CTL) $(LIBTAP) -lm
 
 rotation_SOURCES = rotation.c
index 07c855c9c4130f503d51949ab86815bfab89e313..05db3421a132fd878c58aa8f0c323d6fa35e6d1e 100644 (file)
@@ -20,7 +20,8 @@
 static char *pause_pipe_path;
 static struct lttng_pipe *pause_pipe;
 static int *data_consumption_state;
 static char *pause_pipe_path;
 static struct lttng_pipe *pause_pipe;
 static int *data_consumption_state;
-static enum lttng_consumer_type (*lttng_consumer_get_type)(void);
+using lttng_consumer_get_type_func = enum lttng_consumer_type (*)();
+static lttng_consumer_get_type_func lttng_consumer_get_type;
 
 int lttng_opt_verbose;
 int lttng_opt_mi;
 
 int lttng_opt_verbose;
 int lttng_opt_mi;
diff --git a/tests/regression/tools/notification/notification.c b/tests/regression/tools/notification/notification.c
deleted file mode 100644 (file)
index a56b794..0000000
+++ /dev/null
@@ -1,2689 +0,0 @@
-/*
- * notification.c
- *
- * Tests suite for LTTng notification API
- *
- * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <poll.h>
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-#include <lttng/lttng.h>
-
-#include <tap/tap.h>
-
-#define FIELD_NAME_MAX_LEN 256
-
-/* A callback to populate the condition capture descriptor. */
-typedef int (*condition_capture_desc_cb)(struct lttng_condition *condition);
-
-/* A callback for captured field validation. */
-typedef int (*validate_cb)(const struct lttng_event_field_value *event_field, unsigned iteration);
-
-int nb_args = 0;
-int named_pipe_args_start = 0;
-pid_t app_pid = 0;
-const char *app_state_file = NULL;
-
-enum field_type {
-       FIELD_TYPE_PAYLOAD,
-       FIELD_TYPE_CONTEXT,
-       FIELD_TYPE_APP_CONTEXT,
-       FIELD_TYPE_ARRAY_FIELD,
-};
-
-struct capture_base_field_tuple {
-       char* field_name;
-       enum field_type field_type;
-       /* Do we expect a userspace capture? */
-       bool expected_ust;
-       /* Do we expect a kernel capture? */
-       bool expected_kernel;
-       validate_cb validate_ust;
-       validate_cb validate_kernel;
-};
-
-static
-const char *field_value_type_to_str(enum lttng_event_field_value_type type)
-{
-       switch (type) {
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
-               return "UNKNOWN";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
-               return "INVALID";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
-               return "UNSIGNED INT";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
-               return "SIGNED INT";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
-               return "UNSIGNED ENUM";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
-               return "SIGNED ENUM";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
-               return "REAL";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
-               return "STRING";
-       case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
-               return "ARRAY";
-       default:
-               abort();
-       }
-}
-
-static int validate_type(const struct lttng_event_field_value *event_field,
-               enum lttng_event_field_value_type expect)
-{
-       int ret;
-       enum lttng_event_field_value_type value;
-
-       value = lttng_event_field_value_get_type(event_field);
-       if (value == LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID) {
-               ret = 1;
-               goto end;
-       }
-
-       ok(expect == value, "Expected field type %s, got %s",
-                       field_value_type_to_str(expect),
-                       field_value_type_to_str(value));
-
-       ret = expect != value;
-
-end:
-       return ret;
-}
-
-/*
- * Validate unsigned captured field against the iteration number.
- */
-static int validate_unsigned_int_field(
-               const struct lttng_event_field_value *event_field,
-               unsigned int expected_value)
-{
-       int ret;
-       uint64_t value;
-       enum lttng_event_field_value_status status;
-
-       ret = validate_type(
-                       event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_unsigned_int_get_value(
-                       event_field, &value);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
-                               (int) status);
-               ret = 1;
-               goto end;
-       }
-
-       ok(value == (uint64_t) expected_value,
-                       "Expected unsigned integer value %u, got %" PRIu64,
-                       expected_value, value);
-
-       ret = value != (uint64_t) expected_value;
-
-end:
-       return ret;
-}
-
-/*
- * Validate signed captured field.
- */
-static int validate_signed_int_field(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       int ret;
-       const int64_t expected = -1;
-       int64_t value;
-       enum lttng_event_field_value_status status;
-
-       /* Unused. */
-       (void) iteration;
-
-       ret = validate_type(
-                       event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_signed_int_get_value(
-                       event_field, &value);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_signed_int_get_value returned an error: status = %d",
-                               (int) status);
-               ret = 1;
-               goto end;
-       }
-
-       ok(value == expected,
-                       "Expected signed integer value %" PRId64
-                       ", got %" PRId64,
-                       expected, value);
-
-       ret = value != expected;
-
-end:
-
-       return ret;
-}
-
-/*
- * Validate array of unsigned int.
- */
-static int validate_array_unsigned_int_field(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       int ret;
-       enum lttng_event_field_value_status status;
-       const unsigned int expected = 3;
-       unsigned int i, count;
-
-       /* Unused. */
-       (void) iteration;
-
-       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_array_get_length(event_field, &count);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_array_get_length");
-               ret = 1;
-               goto end;
-       }
-
-       ok(count == expected, "Expected %d subelements, got %d", expected,
-                       count);
-       if (count != expected) {
-               ret = 1;
-               goto end;
-       }
-
-       for (i = 1; i < count + 1; i++) {
-               const struct lttng_event_field_value *value;
-
-               status = lttng_event_field_value_array_get_element_at_index(
-                               event_field, i - 1, &value);
-               if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
-                                       (int) status);
-                       ret = 1;
-                       goto end;
-               }
-
-               ret = validate_unsigned_int_field(value, i);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       ret = 0;
-end:
-
-       return ret;
-}
-
-static int validate_array_unsigned_int_field_at_index(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       int ret;
-       const uint64_t expected_value = 2;
-       enum lttng_event_field_value_status status;
-       uint64_t value;
-
-       /* Unused. */
-       (void) iteration;
-
-       ret = validate_type(
-                       event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_unsigned_int_get_value(
-                       event_field, &value);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
-                               (int) status);
-               ret = 1;
-               goto end;
-       }
-
-       ok(value == expected_value,
-                       "Expected unsigned integer value %u, got %" PRIu64,
-                       expected_value, value);
-
-       ret = 0;
-end:
-       return ret;
-}
-
-/*
- * Validate sequence for a string (seqfield1):
- *
- * Value: "test" encoded in UTF-8: [116, 101, 115, 116]
- */
-static int validate_seqfield1(const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       int ret;
-       enum lttng_event_field_value_status status;
-       unsigned int i, count;
-       const unsigned int expect[] = {116, 101, 115, 116};
-       const size_t array_count = sizeof(expect) / sizeof(*expect);
-
-       /* Unused. */
-       (void) iteration;
-
-       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_array_get_length(event_field, &count);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_array_get_length returned an error: status = %d",
-                               (int) status);
-               ret = 1;
-               goto end;
-       }
-
-       ok(count == array_count, "Expected %zu array sub-elements, got %d",
-                       array_count, count);
-       if (count != array_count) {
-               ret = 1;
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               const struct lttng_event_field_value *value;
-
-               status = lttng_event_field_value_array_get_element_at_index(
-                               event_field, i, &value);
-               if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
-                                       (int) status);
-                       ret = 1;
-                       goto end;
-               }
-
-               ret = validate_unsigned_int_field(value, expect[i]);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       ret = 0;
-end:
-       return ret;
-}
-
-static int validate_string(
-               const struct lttng_event_field_value *event_field,
-               const char *expect)
-{
-       int ret;
-       const char *value = NULL;
-       enum lttng_event_field_value_status status;
-
-       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_STRING);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_string_get_value(event_field, &value);
-       if (!value) {
-               fail("lttng_event_field_value_array_get_length returned an error: status = %d",
-                               (int) status);
-               ret = 1;
-               goto end;
-       }
-
-       ok(!strcmp(value, expect), "Expected string value \"%s\", got \"%s\"",
-                       expect, value);
-
-       ret = 0;
-end:
-
-       return ret;
-}
-
-/*
- * Validate string. Expected value is "test".
- */
-static int validate_string_test(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       const char * const expect = "test";
-
-       /* Unused. */
-       (void) iteration;
-
-       return validate_string(event_field, expect);
-}
-
-/*
- * Validate escaped string. Expected value is "\*".
- */
-static int validate_string_escaped(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       const char * const expect = "\\*";
-
-       /* Unused. */
-       (void) iteration;
-
-       return validate_string(event_field, expect);
-}
-
-/*
- * Validate real field.
- */
-static int validate_real(
-               const struct lttng_event_field_value *event_field,
-               double expect)
-{
-       int ret;
-       double value;
-       enum lttng_event_field_value_status status;
-
-       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_REAL);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_real_get_value(event_field, &value);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_real_get_value returned an error: status = %d",
-                               (int) status);
-               ret = 1;
-               goto end;
-       }
-
-       ok(value == expect, "Expected real value %f, got %f", expect, value);
-       ret = value != expect;
-end:
-       return ret;
-}
-
-/*
- * Validate floatfield.
- */
-static int validate_floatfield(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       const double expect = 2222.0;
-
-       /* Unused. */
-       (void) iteration;
-
-       return validate_real(event_field, expect);
-}
-
-/*
- * Validate doublefield.
- */
-static int validate_doublefield(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       const double expect = 2.0;
-
-       /* Unused. */
-       (void) iteration;
-
-       return validate_real(event_field, expect);
-}
-
-/*
- * Validate enum0: enum0 = ( "AUTO: EXPECT 0" : container = 0 )
- */
-static int validate_enum0(const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       int ret;
-       enum lttng_event_field_value_status status;
-       uint64_t value;
-       const uint64_t expected_value = 0;
-
-       /* Unused. */
-       (void) iteration;
-
-       ret = validate_type(event_field,
-                       LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_unsigned_int_get_value(
-                       event_field, &value);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
-                               (int) status);
-               ret = 1;
-               goto end;
-       }
-
-       ok(value == expected_value,
-                       "Expected enum value %" PRIu64 ", got %" PRIu64,
-                       expected_value, value);
-
-end:
-       return ret;
-}
-
-/*
- * Validate enumnegative: enumnegative = ( "AUTO: EXPECT 0" : container = 0 )
- *
- * We expect 2 labels here.
- */
-static int validate_enumnegative(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       int ret;
-       enum lttng_event_field_value_status status;
-       int64_t value;
-       const int64_t expected_value = -1;
-
-       /* Unused. */
-       (void) iteration;
-
-       ret = validate_type(event_field,
-                       LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_event_field_value_signed_int_get_value(
-                       event_field, &value);
-       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("lttng_event_field_value_unsigned_int_get_value");
-               ret = 1;
-               goto end;
-       }
-
-       ok(value == expected_value,
-                       "Expected enum value %" PRId64 ", got %" PRId64,
-                       expected_value, value);
-
-end:
-       return ret;
-}
-
-static int validate_context_procname_ust(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       /* Unused. */
-       (void) iteration;
-       return validate_string(event_field, "gen-ust-events");
-}
-
-static int validate_context_procname_kernel(
-               const struct lttng_event_field_value *event_field,
-               unsigned int iteration)
-{
-       /* Unused. */
-       (void) iteration;
-       return validate_string(event_field, "echo");
-}
-
-struct capture_base_field_tuple test_capture_base_fields[] = {
-       { "DOESNOTEXIST", FIELD_TYPE_PAYLOAD, false, false, NULL, NULL },
-       { "intfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
-       { "longfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
-       { "signedfield", FIELD_TYPE_PAYLOAD, true, true, validate_signed_int_field, validate_signed_int_field },
-       { "arrfield1", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
-       { "arrfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
-       { "arrfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
-       { "seqfield1", FIELD_TYPE_PAYLOAD, true, true, validate_seqfield1, validate_seqfield1 },
-       { "seqfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
-       { "seqfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
-       { "seqfield4", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
-       { "arrfield1[1]", FIELD_TYPE_ARRAY_FIELD, true, true, validate_array_unsigned_int_field_at_index, validate_array_unsigned_int_field_at_index },
-       { "stringfield", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
-       { "stringfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_escaped, validate_string_escaped },
-       { "floatfield", FIELD_TYPE_PAYLOAD, true, false, validate_floatfield, validate_floatfield },
-       { "doublefield", FIELD_TYPE_PAYLOAD, true, false, validate_doublefield, validate_doublefield },
-       { "enum0", FIELD_TYPE_PAYLOAD, true, true, validate_enum0, validate_enum0 },
-       { "enumnegative", FIELD_TYPE_PAYLOAD, true, true, validate_enumnegative, validate_enumnegative },
-       { "$ctx.procname", FIELD_TYPE_CONTEXT, true, true, validate_context_procname_ust, validate_context_procname_kernel },
-};
-
-static const char *get_notification_trigger_name(
-               struct lttng_notification *notification)
-{
-       const char *trigger_name = NULL;
-       enum lttng_trigger_status trigger_status;
-       const struct lttng_trigger *trigger;
-
-       trigger = lttng_notification_get_trigger(notification);
-       if (!trigger) {
-               fail("Failed to get trigger from notification");
-               goto end;
-       }
-
-       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-       switch (trigger_status) {
-       case LTTNG_TRIGGER_STATUS_OK:
-               break;
-       case LTTNG_TRIGGER_STATUS_UNSET:
-               trigger_name = "(anonymous)";
-               break;
-       default:
-               fail("Failed to get name from notification's trigger");
-               goto end;
-       }
-
-end:
-       return trigger_name;
-}
-
-static int validator_notification_trigger_name(
-               struct lttng_notification *notification,
-               const char *trigger_name)
-{
-       int ret;
-       bool name_is_equal;
-       const char *name;
-
-       LTTNG_ASSERT(notification);
-       LTTNG_ASSERT(trigger_name);
-
-       name = get_notification_trigger_name(notification);
-       if (name == NULL) {
-               ret = 1;
-               goto end;
-       }
-
-       name_is_equal = (strcmp(trigger_name, name) == 0);
-       ok(name_is_equal, "Expected trigger name: %s got %s", trigger_name,
-                       name);
-
-       ret = !name_is_equal;
-
-end:
-       return ret;
-}
-
-static
-void wait_on_file(const char *path, bool file_exist)
-{
-       if (!path) {
-               return;
-       }
-       for (;;) {
-               int ret;
-               struct stat buf;
-
-               ret = stat(path, &buf);
-               if (ret == -1 && errno == ENOENT) {
-                       if (file_exist) {
-                               /*
-                                * The file does not exist. wait a bit and
-                                * continue looping until it does.
-                                */
-                               (void) poll(NULL, 0, 10);
-                               continue;
-                       }
-
-                       /*
-                        * File does not exist and the exit condition we want.
-                        * Break from the loop and return.
-                        */
-                       break;
-               }
-               if (ret) {
-                       perror("stat");
-                       exit(EXIT_FAILURE);
-               }
-               /*
-                * stat() returned 0, so the file exists. break now only if
-                * that's the exit condition we want.
-                */
-               if (file_exist) {
-                       break;
-               }
-       }
-}
-
-static
-int write_pipe(const char *path, uint8_t data)
-{
-       int ret = 0;
-       int fd = 0;
-
-       fd = open(path, O_WRONLY | O_NONBLOCK);
-       if (fd < 0) {
-               perror("Could not open consumer control named pipe");
-               goto end;
-       }
-
-       ret = write(fd, &data , sizeof(data));
-       if (ret < 1) {
-               perror("Named pipe write failed");
-               if (close(fd)) {
-                       perror("Named pipe close failed");
-               }
-               ret = -1;
-               goto end;
-       }
-
-       ret = close(fd);
-       if (ret < 0) {
-               perror("Name pipe closing failed");
-               ret = -1;
-               goto end;
-       }
-end:
-       return ret;
-}
-
-static
-int stop_consumer(const char **argv)
-{
-       int ret = 0, i;
-
-       for (i = named_pipe_args_start; i < nb_args; i++) {
-               ret = write_pipe(argv[i], 49);
-       }
-       return ret;
-}
-
-static
-int resume_consumer(const char **argv)
-{
-       int ret = 0, i;
-
-       for (i = named_pipe_args_start; i < nb_args; i++) {
-               ret = write_pipe(argv[i], 0);
-       }
-       return ret;
-}
-
-static
-int suspend_application(void)
-{
-       int ret;
-       struct stat buf;
-
-       if (!stat(app_state_file, &buf)) {
-               fail("App is already in a suspended state.");
-               ret = -1;
-               goto error;
-       }
-
-       /*
-        * Send SIGUSR1 to application instructing it to bypass tracepoint.
-        */
-       LTTNG_ASSERT(app_pid > 1);
-
-       ret = kill(app_pid, SIGUSR1);
-       if (ret) {
-               fail("SIGUSR1 failed. errno %d", errno);
-               ret = -1;
-               goto error;
-       }
-
-       wait_on_file(app_state_file, true);
-
-error:
-       return ret;
-
-}
-
-static
-int resume_application(void)
-{
-       int ret;
-       struct stat buf;
-
-       ret = stat(app_state_file, &buf);
-       if (ret == -1 && errno == ENOENT) {
-               fail("State file does not exist");
-               goto error;
-       }
-       if (ret) {
-               perror("stat");
-               goto error;
-       }
-
-       LTTNG_ASSERT(app_pid > 1);
-
-       ret = kill(app_pid, SIGUSR1);
-       if (ret) {
-               fail("SIGUSR1 failed. errno %d", errno);
-               ret = -1;
-               goto error;
-       }
-
-       wait_on_file(app_state_file, false);
-
-error:
-       return ret;
-
-}
-
-
-static
-void test_triggers_buffer_usage_condition(const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type,
-               enum lttng_condition_type condition_type)
-{
-       unsigned int test_vector_size = 5, i;
-       enum lttng_condition_status condition_status;
-       struct lttng_action *action;
-
-       /* Set-up */
-       action = lttng_action_notify_create();
-       if (!action) {
-               fail("Setup error on action creation");
-               goto end;
-       }
-
-       /* Test lttng_register_trigger with null value */
-       ok(lttng_register_trigger(NULL) == -LTTNG_ERR_INVALID, "Registering a NULL trigger fails as expected");
-
-       /* Test: register a trigger */
-
-       for (i = 0; i < pow(2,test_vector_size); i++) {
-               int loop_ret = 0;
-               char *test_tuple_string = NULL;
-               unsigned int mask_position = 0;
-               bool session_name_set = false;
-               bool channel_name_set = false;
-               bool threshold_ratio_set = false;
-               bool threshold_byte_set = false;
-               bool domain_type_set = false;
-
-               struct lttng_trigger *trigger = NULL;
-               struct lttng_condition *condition = NULL;
-
-               /* Create base condition */
-               switch (condition_type) {
-               case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
-                       condition = lttng_condition_buffer_usage_low_create();
-                       break;
-               case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
-                       condition = lttng_condition_buffer_usage_high_create();
-                       break;
-               default:
-                       loop_ret = 1;
-                       goto loop_end;
-               }
-
-               if (!condition) {
-                       loop_ret = 1;
-                       goto loop_end;
-
-               }
-
-               /* Prepare the condition for trigger registration test */
-
-               /* Set session name */
-               if ((1 << mask_position) & i) {
-                       condition_status = lttng_condition_buffer_usage_set_session_name(
-                                       condition, session_name);
-                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-                               loop_ret = 1;
-                               goto loop_end;
-                       }
-                       session_name_set = true;
-               }
-               mask_position++;
-
-               /* Set channel name */
-               if ((1 << mask_position) & i) {
-                       condition_status = lttng_condition_buffer_usage_set_channel_name(
-                                       condition, channel_name);
-                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-                               loop_ret = 1;
-                               goto loop_end;
-                       }
-                       channel_name_set = true;
-               }
-               mask_position++;
-
-               /* Set threshold ratio */
-               if ((1 << mask_position) & i) {
-                       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
-                                       condition, 0.0);
-                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-                               loop_ret = 1;
-                               goto loop_end;
-                       }
-                       threshold_ratio_set = true;
-               }
-               mask_position++;
-
-               /* Set threshold byte */
-               if ((1 << mask_position) & i) {
-                       condition_status = lttng_condition_buffer_usage_set_threshold(
-                                       condition, 0);
-                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-                               loop_ret = 1;
-                               goto loop_end;
-                       }
-                       threshold_byte_set = true;
-               }
-               mask_position++;
-
-               /* Set domain type */
-               if ((1 << mask_position) & i) {
-                       condition_status = lttng_condition_buffer_usage_set_domain_type(
-                                       condition, LTTNG_DOMAIN_UST);
-                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-                               loop_ret = 1;
-                               goto loop_end;
-                       }
-                       domain_type_set = true;
-               }
-
-               /* Safety check */
-               if (mask_position != test_vector_size -1) {
-                       LTTNG_ASSERT("Logic error for test vector generation");
-               }
-
-               loop_ret = asprintf(&test_tuple_string, "session name %s, channel name %s, threshold ratio %s, threshold byte %s, domain type %s",
-                               session_name_set ? "set" : "unset",
-                               channel_name_set ? "set" : "unset",
-                               threshold_ratio_set ? "set" : "unset",
-                               threshold_byte_set ? "set" : "unset",
-                               domain_type_set? "set" : "unset");
-               if (!test_tuple_string || loop_ret < 0) {
-                       loop_ret = 1;
-                       goto loop_end;
-               }
-
-               /* Create trigger */
-               trigger = lttng_trigger_create(condition, action);
-               if (!trigger) {
-                       loop_ret = 1;
-                       goto loop_end;
-               }
-
-               loop_ret = lttng_register_trigger(trigger);
-
-loop_end:
-               if (loop_ret == 1) {
-                       fail("Setup error occurred for tuple: %s", test_tuple_string);
-                       goto loop_cleanup;
-               }
-
-               /* This combination happens three times */
-               if (session_name_set && channel_name_set
-                               && (threshold_ratio_set || threshold_byte_set)
-                               && domain_type_set) {
-                       ok(loop_ret == 0, "Trigger is registered: %s", test_tuple_string);
-
-                       /*
-                        * Test that a trigger cannot be registered
-                        * multiple time.
-                        */
-                       loop_ret = lttng_register_trigger(trigger);
-                       ok(loop_ret == -LTTNG_ERR_TRIGGER_EXISTS, "Re-register trigger fails as expected: %s", test_tuple_string);
-
-                       /* Test that a trigger can be unregistered */
-                       loop_ret = lttng_unregister_trigger(trigger);
-                       ok(loop_ret == 0, "Unregister trigger: %s", test_tuple_string);
-
-                       /*
-                        * Test that unregistration of a non-previously
-                        * registered trigger fail.
-                        */
-                       loop_ret = lttng_unregister_trigger(trigger);
-                       ok(loop_ret == -LTTNG_ERR_TRIGGER_NOT_FOUND, "Unregister of a non-registered trigger fails as expected: %s", test_tuple_string);
-               } else {
-                       ok(loop_ret == -LTTNG_ERR_INVALID_TRIGGER, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string);
-               }
-
-loop_cleanup:
-               free(test_tuple_string);
-               lttng_trigger_destroy(trigger);
-               lttng_condition_destroy(condition);
-       }
-
-end:
-       lttng_action_destroy(action);
-}
-
-static
-void wait_data_pending(const char *session_name)
-{
-       int ret;
-
-       do {
-               ret = lttng_data_pending(session_name);
-               LTTNG_ASSERT(ret >= 0);
-       } while (ret != 0);
-}
-
-static
-int setup_buffer_usage_condition(struct lttng_condition *condition,
-               const char *condition_name,
-               const char *session_name,
-               const char *channel_name,
-               const enum lttng_domain_type domain_type)
-{
-       enum lttng_condition_status condition_status;
-       int ret = 0;
-
-       condition_status = lttng_condition_buffer_usage_set_session_name(
-                       condition, session_name);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               fail("Failed to set session name on creation of condition `%s`",
-                               condition_name);
-               ret = -1;
-               goto end;
-       }
-
-       condition_status = lttng_condition_buffer_usage_set_channel_name(
-                       condition, channel_name);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               fail("Failed to set channel name on creation of condition `%s`",
-                               condition_name);
-               ret = -1;
-               goto end;
-       }
-
-       condition_status = lttng_condition_buffer_usage_set_domain_type(
-                       condition, domain_type);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               fail("Failed to set domain type on creation of condition `%s`",
-                               condition_name);
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-void test_invalid_channel_subscription(
-               const enum lttng_domain_type domain_type)
-{
-       enum lttng_condition_status condition_status;
-       enum lttng_notification_channel_status nc_status;
-       struct lttng_condition *dummy_condition = NULL;
-       struct lttng_condition *dummy_invalid_condition = NULL;
-       struct lttng_notification_channel *notification_channel = NULL;
-       int ret = 0;
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-       if (!notification_channel) {
-               goto end;
-       }
-
-       /*
-        * Create a dummy, empty (thus invalid) condition to test error paths.
-        */
-       dummy_invalid_condition = lttng_condition_buffer_usage_low_create();
-       if (!dummy_invalid_condition) {
-               fail("Setup error on condition creation");
-               goto end;
-       }
-
-       /*
-        * Test subscription and unsubscription of an invalid condition to/from
-        * a channel.
-        */
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, dummy_invalid_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
-                       "Subscribing to an invalid condition");
-
-       nc_status = lttng_notification_channel_unsubscribe(
-                       notification_channel, dummy_invalid_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
-                       "Unsubscribing from an invalid condition");
-
-       /* Create a valid dummy condition with a ratio of 0.5 */
-       dummy_condition = lttng_condition_buffer_usage_low_create();
-       if (!dummy_condition) {
-               fail("Setup error on dummy_condition creation");
-               goto end;
-       }
-
-       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
-                       dummy_condition, 0.5);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               fail("Setup error on condition creation");
-               goto end;
-       }
-
-       ret = setup_buffer_usage_condition(dummy_condition, "dummy_condition",
-                       "dummy_session", "dummy_channel", domain_type);
-       if (ret) {
-               fail("Setup error on dummy condition creation");
-               goto end;
-       }
-
-       /*
-        * Test subscription and unsubscription to/from a channel with invalid
-        * parameters.
-        */
-       nc_status = lttng_notification_channel_subscribe(NULL, NULL);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
-                       "Notification channel subscription is invalid: NULL, NULL");
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, NULL);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
-                       "Notification channel subscription is invalid: NON-NULL, NULL");
-
-       nc_status = lttng_notification_channel_subscribe(NULL, dummy_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
-                       "Notification channel subscription is invalid: NULL, NON-NULL");
-
-       nc_status = lttng_notification_channel_unsubscribe(
-                       notification_channel, dummy_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION,
-                       "Unsubscribing from a valid unknown condition");
-
-end:
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_condition_destroy(dummy_invalid_condition);
-       lttng_condition_destroy(dummy_condition);
-       return;
-}
-
-enum buffer_usage_type {
-       BUFFER_USAGE_TYPE_LOW,
-       BUFFER_USAGE_TYPE_HIGH,
-};
-
-static int register_buffer_usage_notify_trigger(const char *session_name,
-               const char *channel_name,
-               const enum lttng_domain_type domain_type,
-               enum buffer_usage_type buffer_usage_type,
-               double ratio,
-               struct lttng_condition **condition,
-               struct lttng_action **action,
-               struct lttng_trigger **trigger)
-{
-       enum lttng_condition_status condition_status;
-       struct lttng_action *tmp_action = NULL;
-       struct lttng_condition *tmp_condition = NULL;
-       struct lttng_trigger *tmp_trigger = NULL;
-       int ret = 0;
-
-       /* Set-up */
-       tmp_action = lttng_action_notify_create();
-       if (!action) {
-               fail("Setup error on action creation");
-               ret = -1;
-               goto error;
-       }
-
-       if (buffer_usage_type == BUFFER_USAGE_TYPE_LOW) {
-               tmp_condition = lttng_condition_buffer_usage_low_create();
-       } else {
-               tmp_condition = lttng_condition_buffer_usage_high_create();
-       }
-
-       if (!tmp_condition) {
-               fail("Setup error on condition creation");
-               ret = -1;
-               goto error;
-       }
-
-       /* Set the buffer usage threashold */
-       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
-                       tmp_condition, ratio);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               fail("Setup error on condition creation");
-               ret = -1;
-               goto error;
-       }
-
-       ret = setup_buffer_usage_condition(tmp_condition, "condition_name",
-                       session_name, channel_name, domain_type);
-       if (ret) {
-               fail("Setup error on condition creation");
-               ret = -1;
-               goto error;
-       }
-
-       /* Register the trigger for condition. */
-       tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
-       if (!tmp_trigger) {
-               fail("Setup error on trigger creation");
-               ret = -1;
-               goto error;
-       }
-
-       ret = lttng_register_trigger(tmp_trigger);
-       if (ret) {
-               fail("Setup error on trigger registration");
-               ret = -1;
-               goto error;
-       }
-
-       *condition = tmp_condition;
-       *trigger = tmp_trigger;
-       *action = tmp_action;
-       goto end;
-
-error:
-       lttng_action_destroy(tmp_action);
-       lttng_condition_destroy(tmp_condition);
-       lttng_trigger_destroy(tmp_trigger);
-
-end:
-       return ret;
-}
-
-static void test_subscription_twice(const char *session_name,
-               const char *channel_name,
-               const enum lttng_domain_type domain_type)
-{
-       int ret = 0;
-       enum lttng_notification_channel_status nc_status;
-
-       struct lttng_action *action = NULL;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_trigger *trigger = NULL;
-
-       struct lttng_condition *condition = NULL;
-
-       ret = register_buffer_usage_notify_trigger(session_name, channel_name,
-                       domain_type, BUFFER_USAGE_TYPE_LOW, 0.99, &condition,
-                       &action, &trigger);
-       if (ret) {
-               fail("Setup error on trigger registration in %s()",
-                               __FUNCTION__);
-               goto end;
-       }
-
-       /* Begin testing. */
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-       if (!notification_channel) {
-               goto end;
-       }
-
-       /* Subscribe a valid condition. */
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to condition");
-
-       /* Subscribing again should fail. */
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED,
-                       "Subscribe to a condition for which subscription was already done");
-
-end:
-       ret = lttng_unregister_trigger(trigger);
-       if (ret) {
-               fail("Failed to unregister trigger in %s()", __FUNCTION__);
-       }
-
-       lttng_trigger_destroy(trigger);
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_action_destroy(action);
-       lttng_condition_destroy(condition);
-}
-
-static void test_buffer_usage_notification_channel(const char *session_name,
-               const char *channel_name,
-               const enum lttng_domain_type domain_type,
-               const char **argv)
-{
-       int ret = 0;
-       enum lttng_notification_channel_status nc_status;
-
-       struct lttng_action *low_action = NULL;
-       struct lttng_action *high_action = NULL;
-       struct lttng_notification *notification = NULL;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_trigger *low_trigger = NULL;
-       struct lttng_trigger *high_trigger = NULL;
-
-       struct lttng_condition *low_condition = NULL;
-       struct lttng_condition *high_condition = NULL;
-
-       const double low_ratio = 0.0;
-       const double high_ratio = 0.90;
-
-       ret = register_buffer_usage_notify_trigger(session_name, channel_name,
-                       domain_type, BUFFER_USAGE_TYPE_LOW, low_ratio,
-                       &low_condition, &low_action, &low_trigger);
-       if (ret) {
-               fail("Setup error on low trigger registration");
-               goto end;
-       }
-
-       ret = register_buffer_usage_notify_trigger(session_name, channel_name,
-                       domain_type, BUFFER_USAGE_TYPE_HIGH, high_ratio,
-                       &high_condition, &high_action, &high_trigger);
-       if (ret) {
-               fail("Setup error on high trigger registration");
-               goto end;
-       }
-
-       /* Begin testing */
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-       if (!notification_channel) {
-               goto end;
-       }
-
-       /* Subscribe a valid low condition */
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, low_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to low condition");
-
-       /* Subscribe a valid high condition */
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, high_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to high condition");
-
-       resume_application();
-
-       /* Wait for notification to happen */
-       stop_consumer(argv);
-       lttng_start_tracing(session_name);
-
-       /* Wait for high notification */
-       do {
-               nc_status = lttng_notification_channel_get_next_notification(
-                               notification_channel, &notification);
-       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
-                                       lttng_condition_get_type(lttng_notification_get_condition(
-                                                       notification)) ==
-                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
-                       "High notification received after intermediary communication");
-       lttng_notification_destroy(notification);
-       notification = NULL;
-
-       suspend_application();
-       lttng_stop_tracing_no_wait(session_name);
-       resume_consumer(argv);
-       wait_data_pending(session_name);
-
-       /*
-        * Test that communication still work even if there is notification
-        * waiting for consumption.
-        */
-
-       nc_status = lttng_notification_channel_unsubscribe(
-                       notification_channel, low_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Unsubscribe with pending notification");
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, low_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe with pending notification");
-
-       do {
-               nc_status = lttng_notification_channel_get_next_notification(
-                               notification_channel, &notification);
-       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
-                                       lttng_condition_get_type(lttng_notification_get_condition(
-                                                       notification)) ==
-                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
-                       "Low notification received after intermediary communication");
-       lttng_notification_destroy(notification);
-       notification = NULL;
-
-       /* Stop consumer to force a high notification */
-       stop_consumer(argv);
-       resume_application();
-       lttng_start_tracing(session_name);
-
-       do {
-               nc_status = lttng_notification_channel_get_next_notification(
-                               notification_channel, &notification);
-       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
-                                       lttng_condition_get_type(lttng_notification_get_condition(
-                                                       notification)) ==
-                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
-                       "High notification received after intermediary communication");
-       lttng_notification_destroy(notification);
-       notification = NULL;
-
-       suspend_application();
-       lttng_stop_tracing_no_wait(session_name);
-       resume_consumer(argv);
-       wait_data_pending(session_name);
-
-       do {
-               nc_status = lttng_notification_channel_get_next_notification(
-                               notification_channel, &notification);
-       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
-                                       lttng_condition_get_type(lttng_notification_get_condition(
-                                                       notification)) ==
-                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
-                       "Low notification received after re-subscription");
-       lttng_notification_destroy(notification);
-       notification = NULL;
-
-       stop_consumer(argv);
-       resume_application();
-       /* Stop consumer to force a high notification */
-       lttng_start_tracing(session_name);
-
-       do {
-               nc_status = lttng_notification_channel_get_next_notification(
-                               notification_channel, &notification);
-       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
-                                       lttng_condition_get_type(lttng_notification_get_condition(
-                                                       notification)) ==
-                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
-                       "High notification");
-       lttng_notification_destroy(notification);
-       notification = NULL;
-
-       suspend_application();
-
-       /* Resume consumer to allow event consumption */
-       lttng_stop_tracing_no_wait(session_name);
-       resume_consumer(argv);
-       wait_data_pending(session_name);
-
-       nc_status = lttng_notification_channel_unsubscribe(
-                       notification_channel, low_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Unsubscribe low condition with pending notification");
-
-       nc_status = lttng_notification_channel_unsubscribe(
-                       notification_channel, high_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Unsubscribe high condition with pending notification");
-
-end:
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_trigger_destroy(low_trigger);
-       lttng_trigger_destroy(high_trigger);
-       lttng_action_destroy(low_action);
-       lttng_action_destroy(high_action);
-       lttng_condition_destroy(low_condition);
-       lttng_condition_destroy(high_condition);
-}
-
-static void create_tracepoint_event_rule_trigger(const char *event_pattern,
-               const char *trigger_name,
-               const char *filter,
-               unsigned int exclusion_count,
-               const char * const *exclusions,
-               enum lttng_domain_type domain_type,
-               condition_capture_desc_cb capture_desc_cb,
-               struct lttng_condition **condition,
-               struct lttng_trigger **trigger)
-{
-       typedef struct lttng_event_rule *(*event_rule_create)(void);
-       typedef enum lttng_event_rule_status (
-                       *event_rule_set_name_pattern)(
-                       struct lttng_event_rule *rule,
-                       const char *pattern);
-       typedef enum lttng_event_rule_status (*event_rule_set_filter)(
-                       struct lttng_event_rule *rule,
-                       const char *expression);
-       typedef enum lttng_event_rule_status (
-                       *event_rule_add_name_pattern_exclusion)(
-                       struct lttng_event_rule * rule, const char *exclusion);
-
-       enum lttng_event_rule_status event_rule_status;
-       struct lttng_action *tmp_action = NULL;
-       struct lttng_event_rule *event_rule = NULL;
-       struct lttng_condition *tmp_condition = NULL;
-       struct lttng_trigger *tmp_trigger = NULL;
-       int ret;
-       enum lttng_error_code ret_code;
-       event_rule_create create;
-       event_rule_set_name_pattern set_name_pattern;
-       event_rule_set_filter set_filter;
-       event_rule_add_name_pattern_exclusion add_name_pattern_exclusion;
-
-       LTTNG_ASSERT(event_pattern);
-       LTTNG_ASSERT(trigger_name);
-       LTTNG_ASSERT(condition);
-       LTTNG_ASSERT(trigger);
-
-       /* Set the function pointers based on the domain type. */
-       switch (domain_type) {
-       case LTTNG_DOMAIN_UST:
-               create = lttng_event_rule_user_tracepoint_create;
-               set_name_pattern = lttng_event_rule_user_tracepoint_set_name_pattern;
-               set_filter = lttng_event_rule_user_tracepoint_set_filter;
-               add_name_pattern_exclusion = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion;
-               break;
-       case LTTNG_DOMAIN_KERNEL:
-               create = lttng_event_rule_kernel_tracepoint_create;
-               set_name_pattern = lttng_event_rule_kernel_tracepoint_set_name_pattern;
-               set_filter = lttng_event_rule_kernel_tracepoint_set_filter;
-               add_name_pattern_exclusion = NULL;
-               break;
-       default:
-               abort();
-               break;
-       }
-
-       event_rule = create();
-       ok(event_rule, "Tracepoint event rule object creation");
-
-       event_rule_status = set_name_pattern(event_rule, event_pattern);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting tracepoint event rule pattern: '%s'",
-                       event_pattern);
-
-       if (filter) {
-               event_rule_status = set_filter(event_rule, filter);
-               ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                               "Setting tracepoint event rule filter: '%s'",
-                               filter);
-       }
-
-       if (exclusions) {
-               int i;
-               bool success = true;
-
-               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
-               LTTNG_ASSERT(add_name_pattern_exclusion != NULL);
-               LTTNG_ASSERT(exclusion_count > 0);
-
-               for (i = 0; i < exclusion_count; i++) {
-                       event_rule_status = add_name_pattern_exclusion(
-                                       event_rule, exclusions[i]);
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               fail("Setting tracepoint event rule exclusion '%s'.",
-                                               exclusions[i]);
-                               success = false;
-                       }
-               }
-
-               ok(success, "Setting tracepoint event rule exclusions");
-       }
-
-       tmp_condition = lttng_condition_event_rule_matches_create(event_rule);
-       ok(tmp_condition, "Condition event rule object creation");
-
-       if (capture_desc_cb) {
-               ret = capture_desc_cb(tmp_condition);
-               if (ret) {
-                       fail("Failed to generate the condition capture descriptor");
-                       abort();
-               }
-       }
-
-       tmp_action = lttng_action_notify_create();
-       ok(tmp_action, "Action event rule object creation");
-
-       tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
-       ok(tmp_trigger, "Trigger object creation %s", trigger_name);
-
-       ret_code = lttng_register_trigger_with_name(tmp_trigger, trigger_name);
-       ok(ret_code == LTTNG_OK, "Trigger registration %s", trigger_name);
-
-       lttng_event_rule_destroy(event_rule);
-
-       *condition = tmp_condition;
-       *trigger = tmp_trigger;
-
-       return;
-}
-
-static struct lttng_notification *get_next_notification(
-               struct lttng_notification_channel *notification_channel)
-{
-       struct lttng_notification *local_notification = NULL;
-       enum lttng_notification_channel_status status;
-
-       /* Receive the next notification. */
-       status = lttng_notification_channel_get_next_notification(
-                       notification_channel, &local_notification);
-
-       switch (status) {
-       case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
-               break;
-       case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
-               fail("Notifications have been dropped");
-               local_notification = NULL;
-               break;
-       default:
-               /* Unhandled conditions / errors. */
-               fail("Failed to get next notification (unknown notification channel status): status = %d",
-                               (int) status);
-               local_notification = NULL;
-               break;
-       }
-
-       return local_notification;
-}
-
-static void test_tracepoint_event_rule_notification(
-               enum lttng_domain_type domain_type)
-{
-       int i;
-       int ret;
-       const int notification_count = 3;
-       enum lttng_notification_channel_status nc_status;
-       struct lttng_action *action = NULL;
-       struct lttng_condition *condition = NULL;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_trigger *trigger = NULL;
-       const char * const trigger_name = "my_precious";
-       const char *pattern;
-
-       if (domain_type == LTTNG_DOMAIN_UST) {
-               pattern = "tp:tptest";
-       } else {
-               pattern = "lttng_test_filter_event";
-       }
-
-       create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
-                       NULL, domain_type, NULL, &condition, &trigger);
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       resume_application();
-
-       /* Get notifications. */
-       for (i = 0; i < notification_count; i++) {
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-
-               ok(notification, "Received notification (%d/%d)", i + 1,
-                               notification_count);
-
-               /* Error. */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               ret = validator_notification_trigger_name(notification, trigger_name);
-               lttng_notification_destroy(notification);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       suspend_application();
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_unregister_trigger(trigger);
-       lttng_trigger_destroy(trigger);
-       lttng_action_destroy(action);
-       lttng_condition_destroy(condition);
-       return;
-}
-
-static void test_tracepoint_event_rule_notification_filter(
-               enum lttng_domain_type domain_type)
-{
-       int i;
-       const int notification_count = 3;
-       enum lttng_notification_channel_status nc_status;
-       struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
-       const char * const ctrl_trigger_name = "control_trigger";
-       const char * const trigger_name = "trigger";
-       const char *pattern;
-       int ctrl_count = 0, count = 0;
-
-       if (domain_type == LTTNG_DOMAIN_UST) {
-               pattern = "tp:tptest";
-       } else {
-               pattern = "lttng_test_filter_event";
-       }
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
-                       0, NULL, domain_type, NULL, &ctrl_condition, &ctrl_trigger);
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, ctrl_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       /*
-        * Attach a filter expression to get notification only if the
-        * `intfield` is even.
-        */
-       create_tracepoint_event_rule_trigger(pattern, trigger_name,
-                       "(intfield & 1) == 0", 0, NULL, domain_type, NULL, &condition,
-                       &trigger);
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       /*
-        * We registered 2 notifications triggers, one with a filter and one
-        * without (control). The one with a filter will only fired when the
-        * `intfield` is a multiple of 2. We should get two times as many
-        * control notifications as filter notifications.
-        */
-       resume_application();
-
-       /*
-        * Get 3 notifications. We should get 1 for the regular trigger (with
-        * the filter) and 2 from the control trigger. This works whatever
-        * the order we receive the notifications.
-        */
-       for (i = 0; i < notification_count; i++) {
-               const char *name;
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-
-               ok(notification, "Received notification (%d/%d)", i + 1,
-                               notification_count);
-
-               /* Error. */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               name = get_notification_trigger_name(notification);
-               if (name == NULL) {
-                       lttng_notification_destroy(notification);
-                       goto end;
-               }
-
-               if (strcmp(ctrl_trigger_name, name) == 0) {
-                       ctrl_count++;
-               } else if (strcmp(trigger_name, name) == 0) {
-                       count++;
-               }
-
-               lttng_notification_destroy(notification);
-       }
-
-       ok(ctrl_count / 2 == count,
-                       "Get twice as many control notif as of regular notif");
-
-end:
-       suspend_application();
-
-       lttng_unregister_trigger(trigger);
-       lttng_unregister_trigger(ctrl_trigger);
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_trigger_destroy(trigger);
-       lttng_trigger_destroy(ctrl_trigger);
-       lttng_condition_destroy(condition);
-       lttng_condition_destroy(ctrl_condition);
-}
-
-static void test_tracepoint_event_rule_notification_exclusion(
-               enum lttng_domain_type domain_type)
-{
-       enum lttng_notification_channel_status nc_status;
-       struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
-       int ctrl_count = 0, count = 0, i;
-       const int notification_count = 6;
-       const char * const ctrl_trigger_name = "control_exclusion_trigger";
-       const char * const trigger_name = "exclusion_trigger";
-       const char * const pattern = "tp:tptest*";
-       const char * const exclusions[] = {
-               "tp:tptest2",
-               "tp:tptest3",
-               "tp:tptest4",
-               "tp:tptest5"
-       };
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
-                       0, NULL, domain_type, NULL, &ctrl_condition,
-                       &ctrl_trigger);
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, ctrl_condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 4,
-                       exclusions, domain_type, NULL, &condition,
-                       &trigger);
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       /*
-        * We registered 2 notifications triggers, one with an exclusion and
-        * one without (control).
-        * - The trigger with an exclusion will fire once every iteration.
-        * - The trigger without an exclusion will fire 5 times every
-        *   iteration.
-        *
-        *   We should get 5 times as many notifications from the control
-        *   trigger.
-        */
-       resume_application();
-
-       /*
-        * Get 6 notifications. We should get 1 for the regular trigger (with
-        * the exclusion) and 5 from the control trigger. This works whatever
-        * the order we receive the notifications.
-        */
-       for (i = 0; i < notification_count; i++) {
-               const char *name;
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-
-               ok(notification, "Received notification (%d/%d)", i + 1,
-                               notification_count);
-
-               /* Error. */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               name = get_notification_trigger_name(notification);
-               if (name == NULL) {
-                       lttng_notification_destroy(notification);
-                       goto end;
-               }
-
-               if (strcmp(ctrl_trigger_name, name) == 0) {
-                       ctrl_count++;
-               } else if (strcmp(trigger_name, name) == 0) {
-                       count++;
-               }
-
-               lttng_notification_destroy(notification);
-       }
-
-       ok(ctrl_count / 5 == count,
-                       "Got 5 times as many control notif as of regular notif");
-
-end:
-       suspend_application();
-
-       lttng_unregister_trigger(trigger);
-       lttng_unregister_trigger(ctrl_trigger);
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_trigger_destroy(trigger);
-       lttng_trigger_destroy(ctrl_trigger);
-       lttng_condition_destroy(condition);
-       lttng_condition_destroy(ctrl_condition);
-       return;
-}
-
-static void test_kprobe_event_rule_notification(
-               enum lttng_domain_type domain_type)
-{
-       int i, ret;
-       enum lttng_error_code ret_code;
-       const int notification_count = 3;
-       enum lttng_notification_channel_status nc_status;
-       enum lttng_event_rule_status event_rule_status;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_condition *condition = NULL;
-       struct lttng_kernel_probe_location *location = NULL;
-       struct lttng_event_rule *event_rule = NULL;
-       struct lttng_action *action = NULL;
-       struct lttng_trigger *trigger = NULL;
-       const char * const trigger_name = "kprobe_trigger";
-       const char * const symbol_name = "lttng_test_filter_event_write";
-
-       action = lttng_action_notify_create();
-       if (!action) {
-               fail("Failed to create notify action");
-               goto end;
-       }
-
-       location = lttng_kernel_probe_location_symbol_create(symbol_name, 0);
-       if (!location) {
-               fail("Failed to create kernel probe location");
-               goto end;
-       }
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       event_rule = lttng_event_rule_kernel_kprobe_create(location);
-       ok(event_rule, "kprobe event rule object creation");
-
-       event_rule_status = lttng_event_rule_kernel_kprobe_set_event_name(
-                       event_rule, trigger_name);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting kprobe event rule name: '%s'", trigger_name);
-
-       condition = lttng_condition_event_rule_matches_create(event_rule);
-       ok(condition, "Condition event rule object creation");
-
-       /* Register the trigger for condition. */
-       trigger = lttng_trigger_create(condition, action);
-       if (!trigger) {
-               fail("Failed to create trigger with kernel probe event rule condition and notify action");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to register trigger with kernel probe event rule condition and notify action");
-               goto end;
-       }
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       resume_application();
-
-       for (i = 0; i < notification_count; i++) {
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-
-               ok(notification, "Received notification (%d/%d)", i + 1,
-                               notification_count);
-
-               /* Error. */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               ret = validator_notification_trigger_name(notification, trigger_name);
-               lttng_notification_destroy(notification);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       suspend_application();
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_unregister_trigger(trigger);
-       lttng_trigger_destroy(trigger);
-       lttng_action_destroy(action);
-       lttng_event_rule_destroy(event_rule);
-       lttng_condition_destroy(condition);
-       lttng_kernel_probe_location_destroy(location);
-       return;
-}
-
-static void test_uprobe_event_rule_notification(
-               enum lttng_domain_type domain_type,
-               const char *testapp_path,
-               const char *test_symbol_name)
-{
-       int i, ret;
-       enum lttng_error_code ret_code;
-       const int notification_count = 3;
-       enum lttng_notification_channel_status nc_status;
-       enum lttng_event_rule_status event_rule_status;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_userspace_probe_location *probe_location = NULL;
-       struct lttng_userspace_probe_location_lookup_method *lookup_method =
-                       NULL;
-       struct lttng_condition *condition = NULL;
-       struct lttng_event_rule *event_rule = NULL;
-       struct lttng_action *action = NULL;
-       struct lttng_trigger *trigger = NULL;
-       const char * const trigger_name = "uprobe_trigger";
-
-       action = lttng_action_notify_create();
-       if (!action) {
-               fail("Failed to create notify action");
-               goto end;
-       }
-
-       lookup_method = lttng_userspace_probe_location_lookup_method_function_elf_create();
-       if (!lookup_method) {
-               fail("Setup error on userspace probe lookup method creation");
-               goto end;
-       }
-
-       probe_location = lttng_userspace_probe_location_function_create(
-                       testapp_path, test_symbol_name, lookup_method);
-       if (!probe_location) {
-               fail("Failed to create userspace probe location");
-               goto end;
-       }
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       event_rule = lttng_event_rule_kernel_uprobe_create(probe_location);
-       ok(event_rule, "kprobe event rule object creation");
-
-       event_rule_status = lttng_event_rule_kernel_uprobe_set_event_name(
-                       event_rule, trigger_name);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting uprobe event rule name: '%s'", trigger_name);
-
-       condition = lttng_condition_event_rule_matches_create(event_rule);
-       ok(condition, "Condition event rule object creation");
-
-       /* Register the trigger for condition. */
-       trigger = lttng_trigger_create(condition, action);
-       if (!trigger) {
-               fail("Failed to create trigger with userspace probe event rule condition and notify action");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to register trigger with userspace probe event rule condition and notify action");
-               goto end;
-       }
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       resume_application();
-
-       for (i = 0; i < 3; i++) {
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-
-               ok(notification, "Received notification (%d/%d)", i + 1,
-                               notification_count);
-
-               /* Error. */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               ret = validator_notification_trigger_name(notification, trigger_name);
-               lttng_notification_destroy(notification);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       suspend_application();
-
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_unregister_trigger(trigger);
-       lttng_trigger_destroy(trigger);
-       lttng_action_destroy(action);
-       lttng_userspace_probe_location_destroy(probe_location);
-       lttng_event_rule_destroy(event_rule);
-       lttng_condition_destroy(condition);
-       return;
-}
-
-static void test_syscall_event_rule_notification(
-               enum lttng_domain_type domain_type)
-{
-       int i, ret;
-       enum lttng_error_code ret_code;
-       const int notification_count = 3;
-       enum lttng_notification_channel_status nc_status;
-       enum lttng_event_rule_status event_rule_status;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_condition *condition = NULL;
-       struct lttng_event_rule *event_rule = NULL;
-       struct lttng_action *action = NULL;
-       struct lttng_trigger *trigger = NULL;
-       const char * const trigger_name = "syscall_trigger";
-       const char * const syscall_name = "openat";
-
-       action = lttng_action_notify_create();
-       if (!action) {
-               fail("Failed to create notify action");
-               goto end;
-       }
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
-       ok(event_rule, "syscall event rule object creation");
-
-       event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
-                       event_rule, syscall_name);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting syscall event rule pattern: '%s'", syscall_name);
-
-       condition = lttng_condition_event_rule_matches_create(event_rule);
-       ok(condition, "Condition syscall event rule object creation");
-
-       /* Register the trigger for condition. */
-       trigger = lttng_trigger_create(condition, action);
-       if (!trigger) {
-               fail("Failed to create trigger with syscall event rule condition and notify action");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to register trigger with syscall event rule condition and notify action");
-               goto end;
-       }
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       resume_application();
-
-       for (i = 0; i < notification_count; i++) {
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-
-               ok(notification, "Received notification (%d/%d)", i + 1,
-                               notification_count);
-
-               /* Error. */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               ret = validator_notification_trigger_name(notification, trigger_name);
-               lttng_notification_destroy(notification);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       suspend_application();
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_unregister_trigger(trigger);
-       lttng_trigger_destroy(trigger);
-       lttng_action_destroy(action);
-       lttng_condition_destroy(condition);
-       return;
-}
-
-static void test_syscall_event_rule_notification_filter(
-               enum lttng_domain_type domain_type)
-{
-       int i, ret;
-       enum lttng_error_code ret_code;
-       const int notification_count = 3;
-       enum lttng_notification_channel_status nc_status;
-       enum lttng_event_rule_status event_rule_status;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_condition *condition = NULL;
-       struct lttng_event_rule *event_rule = NULL;
-       struct lttng_action *action = NULL;
-       struct lttng_trigger *trigger = NULL;
-       const char * const trigger_name = "syscall_trigger";
-       const char * const syscall_name = "openat";
-       const char * const filter_pattern = "filename == \"/proc/cpuinfo\"";
-
-       action = lttng_action_notify_create();
-       if (!action) {
-               fail("Failed to create notify action");
-               goto end;
-       }
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
-       ok(event_rule, "syscall event rule object creation");
-
-       event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
-                       event_rule, syscall_name);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting syscall event rule pattern: '%s'", syscall_name);
-
-       event_rule_status = lttng_event_rule_kernel_syscall_set_filter(
-                       event_rule, filter_pattern);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting filter: '%s'", filter_pattern);
-
-       condition = lttng_condition_event_rule_matches_create(event_rule);
-       ok(condition, "Condition event rule object creation");
-
-       /* Register the triggers for condition */
-       trigger = lttng_trigger_create(condition, action);
-       if (!trigger) {
-               fail("Failed to create trigger with syscall filtering event rule condition and notify action");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to register trigger with syscall filtering event rule condition and notify action");
-               goto end;
-       }
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       resume_application();
-
-       for (i = 0; i < notification_count; i++) {
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-
-               ok(notification, "Received notification (%d/%d)", i + 1,
-                               notification_count);
-
-               /* Error. */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               ret = validator_notification_trigger_name(notification, trigger_name);
-               lttng_notification_destroy(notification);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       suspend_application();
-
-       lttng_unregister_trigger(trigger);
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_trigger_destroy(trigger);
-       lttng_event_rule_destroy(event_rule);
-       lttng_condition_destroy(condition);
-       return;
-}
-
-static int generate_capture_descr(struct lttng_condition *condition)
-{
-       int ret, i;
-       struct lttng_event_expr *expr = NULL;
-       const unsigned int basic_field_count = sizeof(test_capture_base_fields) /
-                       sizeof(*test_capture_base_fields);
-       enum lttng_condition_status cond_status;
-
-       for (i = 0; i < basic_field_count; i++) {
-               diag("Adding capture descriptor '%s'",
-                               test_capture_base_fields[i].field_name);
-
-               switch (test_capture_base_fields[i].field_type) {
-               case FIELD_TYPE_PAYLOAD:
-                       expr = lttng_event_expr_event_payload_field_create(
-                                       test_capture_base_fields[i].field_name);
-                       break;
-               case FIELD_TYPE_CONTEXT:
-                       expr = lttng_event_expr_channel_context_field_create(
-                                       test_capture_base_fields[i].field_name);
-                       break;
-               case FIELD_TYPE_ARRAY_FIELD:
-               {
-                       int nb_matches;
-                       unsigned int index;
-                       char field_name[FIELD_NAME_MAX_LEN];
-                       struct lttng_event_expr *array_expr = NULL;
-
-                       nb_matches = sscanf(test_capture_base_fields[i].field_name,
-                                       "%[^[][%u]", field_name, &index);
-                       if (nb_matches != 2) {
-                               fail("Unexpected array field name format: field name = '%s'",
-                                               test_capture_base_fields[i].field_name);
-                               ret = 1;
-                               goto end;
-                       }
-
-                       array_expr = lttng_event_expr_event_payload_field_create(
-                               field_name);
-
-                       expr = lttng_event_expr_array_field_element_create(
-                               array_expr, index);
-                       break;
-               }
-               case FIELD_TYPE_APP_CONTEXT:
-                       fail("Application context tests are not implemented yet.");
-                       /* fallthrough. */
-               default:
-                       ret = 1;
-                       goto end;
-               }
-
-               if (expr == NULL) {
-                       fail("Failed to create capture expression");
-                       ret = -1;
-                       goto end;
-               }
-
-               cond_status = lttng_condition_event_rule_matches_append_capture_descriptor(
-                               condition, expr);
-               if (cond_status != LTTNG_CONDITION_STATUS_OK) {
-                       fail("Failed to append capture descriptor");
-                       ret = -1;
-                       lttng_event_expr_destroy(expr);
-                       goto end;
-               }
-       }
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static int validator_notification_trigger_capture(
-               enum lttng_domain_type domain,
-               struct lttng_notification *notification,
-               const int iteration)
-{
-       int ret;
-       unsigned int capture_count, i;
-       enum lttng_evaluation_event_rule_matches_status
-                       event_rule_matches_evaluation_status;
-       enum lttng_event_field_value_status event_field_value_status;
-       const struct lttng_evaluation *evaluation;
-       const struct lttng_event_field_value *captured_fields;
-       bool at_least_one_error = false;
-
-       evaluation = lttng_notification_get_evaluation(notification);
-       if (evaluation == NULL) {
-               fail("Failed to get evaluation from notification during trigger capture test");
-               ret = 1;
-               goto end;
-       }
-
-       event_rule_matches_evaluation_status =
-                       lttng_evaluation_event_rule_matches_get_captured_values(
-                                       evaluation, &captured_fields);
-       if (event_rule_matches_evaluation_status !=
-                       LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
-               diag("Failed to get event rule evaluation captured values: status = %d",
-                               (int) event_rule_matches_evaluation_status);
-               ret = 1;
-               goto end;
-       }
-
-       event_field_value_status =
-               lttng_event_field_value_array_get_length(captured_fields,
-                               &capture_count);
-       if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-               fail("Failed to get count of captured value field array");
-               ret = 1;
-               goto end;
-       }
-
-       for (i = 0; i < capture_count; i++) {
-               const struct lttng_event_field_value *captured_field = NULL;
-               validate_cb validate;
-               bool expected;
-
-               diag("Validating capture of field '%s'",
-                               test_capture_base_fields[i].field_name);
-               event_field_value_status =
-                               lttng_event_field_value_array_get_element_at_index(
-                                               captured_fields, i,
-                                               &captured_field);
-
-               switch(domain) {
-               case LTTNG_DOMAIN_UST:
-                       expected = test_capture_base_fields[i].expected_ust;
-                       break;
-               case LTTNG_DOMAIN_KERNEL:
-                       expected = test_capture_base_fields[i].expected_kernel;
-                       break;
-               default:
-                       fail("Unexpected domain encountered: domain = %d",
-                                       (int) domain);
-                       ret = 1;
-                       goto end;
-               }
-
-               if (domain == LTTNG_DOMAIN_UST) {
-                       validate = test_capture_base_fields[i].validate_ust;
-               } else {
-                       validate = test_capture_base_fields[i].validate_kernel;
-               }
-
-               if (!expected) {
-                       ok(event_field_value_status == LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE,
-                                       "No payload captured");
-                       continue;
-               }
-
-               if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
-                       if (event_field_value_status ==
-                                       LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
-                               fail("Expected a capture but it is unavailable");
-                       } else {
-                               fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
-                                               (int) event_field_value_status);
-                       }
-
-                       ret = 1;
-                       goto end;
-               }
-
-               diag("Captured field of type %s",
-                               field_value_type_to_str(
-                                       lttng_event_field_value_get_type(captured_field)));
-
-               LTTNG_ASSERT(validate);
-               ret = validate(captured_field, iteration);
-               if (ret) {
-                       at_least_one_error = true;
-               }
-       }
-
-       ret = at_least_one_error;
-
-end:
-       return ret;
-}
-
-static void test_tracepoint_event_rule_notification_capture(
-               enum lttng_domain_type domain_type)
-{
-       enum lttng_notification_channel_status nc_status;
-
-       int i, ret;
-       struct lttng_condition *condition = NULL;
-       struct lttng_notification_channel *notification_channel = NULL;
-       struct lttng_trigger *trigger = NULL;
-       const char *trigger_name = "my_precious";
-       const char *pattern;
-
-       if (domain_type == LTTNG_DOMAIN_UST) {
-               pattern = "tp:tptest";
-       } else {
-               pattern = "lttng_test_filter_event";
-       }
-
-       create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
-                       NULL, domain_type, generate_capture_descr, &condition,
-                       &trigger);
-
-       notification_channel = lttng_notification_channel_create(
-                       lttng_session_daemon_notification_endpoint);
-       ok(notification_channel, "Notification channel object creation");
-
-       nc_status = lttng_notification_channel_subscribe(
-                       notification_channel, condition);
-       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
-                       "Subscribe to tracepoint event rule condition");
-
-       resume_application();
-
-       /* Get 3 notifications */
-       for (i = 0; i < 3; i++) {
-               struct lttng_notification *notification = get_next_notification(
-                               notification_channel);
-               ok(notification, "Received notification");
-
-               /* Error */
-               if (notification == NULL) {
-                       goto end;
-               }
-
-               ret = validator_notification_trigger_name(notification, trigger_name);
-               if (ret) {
-                       lttng_notification_destroy(notification);
-                       goto end;
-               }
-
-               ret = validator_notification_trigger_capture(domain_type, notification, i);
-               if (ret) {
-                       lttng_notification_destroy(notification);
-                       goto end;
-               }
-
-               lttng_notification_destroy(notification);
-       }
-
-end:
-       suspend_application();
-       lttng_notification_channel_destroy(notification_channel);
-       lttng_unregister_trigger(trigger);
-       lttng_trigger_destroy(trigger);
-       lttng_condition_destroy(condition);
-       return;
-}
-
-int main(int argc, const char *argv[])
-{
-       int test_scenario;
-       const char *domain_type_string = NULL;
-       enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
-
-       if (argc < 5) {
-               fail("Missing test scenario, domain type, pid, or application state file argument(s)");
-               goto error;
-       }
-
-       test_scenario = atoi(argv[1]);
-       domain_type_string = argv[2];
-       app_pid = (pid_t) atoi(argv[3]);
-       app_state_file = argv[4];
-
-       if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string)) {
-               domain_type = LTTNG_DOMAIN_UST;
-       }
-       if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
-               domain_type = LTTNG_DOMAIN_KERNEL;
-       }
-       if (domain_type == LTTNG_DOMAIN_NONE) {
-               fail("Unknown domain type");
-               goto error;
-       }
-
-       /*
-        * Test cases are responsible for resuming the app when needed
-        * and making sure it's suspended when returning.
-        */
-       suspend_application();
-
-       switch (test_scenario) {
-       case 1:
-       {
-               plan_tests(41);
-
-               /* Test cases that need gen-ust-event testapp. */
-               diag("Test basic notification error paths for %s domain",
-                               domain_type_string);
-               test_invalid_channel_subscription(domain_type);
-
-               diag("Test tracepoint event rule notifications for domain %s",
-                               domain_type_string);
-               test_tracepoint_event_rule_notification(domain_type);
-
-               diag("Test tracepoint event rule notifications with filter for domain %s",
-                               domain_type_string);
-               test_tracepoint_event_rule_notification_filter(domain_type);
-               break;
-       }
-       case 2:
-       {
-               const char *session_name, *channel_name;
-
-               /* Test cases that need a tracing session enabled. */
-               plan_tests(99);
-
-               /*
-                * Argument 7 and upward are named pipe location for consumerd
-                * control.
-                */
-               named_pipe_args_start = 7;
-
-               if (argc < 8) {
-                       fail("Missing parameter for tests to run %d", argc);
-                       goto error;
-               }
-
-               nb_args = argc;
-
-               session_name = argv[5];
-               channel_name = argv[6];
-
-               test_subscription_twice(session_name, channel_name,
-                               domain_type);
-
-               diag("Test trigger for domain %s with buffer_usage_low condition",
-                               domain_type_string);
-               test_triggers_buffer_usage_condition(session_name, channel_name,
-                               domain_type,
-                               LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
-
-               diag("Test trigger for domain %s with buffer_usage_high condition",
-                               domain_type_string);
-               test_triggers_buffer_usage_condition(session_name, channel_name,
-                               domain_type,
-                               LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
-
-               diag("Test buffer usage notification channel api for domain %s",
-                               domain_type_string);
-               test_buffer_usage_notification_channel(session_name, channel_name,
-                               domain_type, argv);
-               break;
-       }
-       case 3:
-       {
-               /*
-                * Test cases that need a test app with more than one event
-                * type.
-                */
-               plan_tests(23);
-
-               /*
-                * At the moment, the only test case of this scenario is
-                * exclusion which is only supported by UST.
-                */
-               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
-               diag("Test tracepoint event rule notifications with exclusion for domain %s",
-                               domain_type_string);
-               test_tracepoint_event_rule_notification_exclusion(domain_type);
-
-               break;
-       }
-       case 4:
-       {
-               plan_tests(11);
-               /* Test cases that need the kernel tracer. */
-               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
-
-               diag("Test kprobe event rule notifications for domain %s",
-                               domain_type_string);
-
-               test_kprobe_event_rule_notification(domain_type);
-
-               break;
-       }
-       case 5:
-       {
-               plan_tests(23);
-               /* Test cases that need the kernel tracer. */
-               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
-
-               diag("Test syscall event rule notifications for domain %s",
-                               domain_type_string);
-
-               test_syscall_event_rule_notification(domain_type);
-
-               diag("Test syscall filtering event rule notifications for domain %s",
-                               domain_type_string);
-
-               test_syscall_event_rule_notification_filter(domain_type);
-
-               break;
-       }
-       case 6:
-       {
-               const char *testapp_path, *test_symbol_name;
-
-               plan_tests(11);
-
-               if (argc < 7) {
-                       fail("Missing parameter for tests to run %d", argc);
-                       goto error;
-               }
-
-               testapp_path = argv[5];
-               test_symbol_name = argv[6];
-               /* Test cases that need the kernel tracer. */
-               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
-
-               diag("Test userspace-probe event rule notifications for domain %s",
-                               domain_type_string);
-
-               test_uprobe_event_rule_notification(
-                               domain_type, testapp_path, test_symbol_name);
-
-               break;
-       }
-       case 7:
-       {
-               switch(domain_type) {
-               case LTTNG_DOMAIN_UST:
-                       plan_tests(221);
-                       break;
-               case LTTNG_DOMAIN_KERNEL:
-                       plan_tests(215);
-                       break;
-               default:
-                       abort();
-               }
-
-               diag("Test tracepoint event rule notification captures for domain %s",
-                               domain_type_string);
-               test_tracepoint_event_rule_notification_capture(domain_type);
-
-               break;
-       }
-
-       default:
-               abort();
-       }
-
-error:
-       return exit_status();
-}
-
diff --git a/tests/regression/tools/notification/notification.cpp b/tests/regression/tools/notification/notification.cpp
new file mode 100644 (file)
index 0000000..7a0b5dc
--- /dev/null
@@ -0,0 +1,2689 @@
+/*
+ * notification.c
+ *
+ * Tests suite for LTTng notification API
+ *
+ * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <poll.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+#include <lttng/lttng.h>
+
+#include <tap/tap.h>
+
+#define FIELD_NAME_MAX_LEN 256
+
+/* A callback to populate the condition capture descriptor. */
+typedef int (*condition_capture_desc_cb)(struct lttng_condition *condition);
+
+/* A callback for captured field validation. */
+typedef int (*validate_cb)(const struct lttng_event_field_value *event_field, unsigned iteration);
+
+int nb_args = 0;
+int named_pipe_args_start = 0;
+pid_t app_pid = 0;
+const char *app_state_file = NULL;
+
+enum field_type {
+       FIELD_TYPE_PAYLOAD,
+       FIELD_TYPE_CONTEXT,
+       FIELD_TYPE_APP_CONTEXT,
+       FIELD_TYPE_ARRAY_FIELD,
+};
+
+struct capture_base_field_tuple {
+       const char *field_name;
+       enum field_type field_type;
+       /* Do we expect a userspace capture? */
+       bool expected_ust;
+       /* Do we expect a kernel capture? */
+       bool expected_kernel;
+       validate_cb validate_ust;
+       validate_cb validate_kernel;
+};
+
+static
+const char *field_value_type_to_str(enum lttng_event_field_value_type type)
+{
+       switch (type) {
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
+               return "UNKNOWN";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
+               return "INVALID";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
+               return "UNSIGNED INT";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
+               return "SIGNED INT";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+               return "UNSIGNED ENUM";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+               return "SIGNED ENUM";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
+               return "REAL";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
+               return "STRING";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
+               return "ARRAY";
+       default:
+               abort();
+       }
+}
+
+static int validate_type(const struct lttng_event_field_value *event_field,
+               enum lttng_event_field_value_type expect)
+{
+       int ret;
+       enum lttng_event_field_value_type value;
+
+       value = lttng_event_field_value_get_type(event_field);
+       if (value == LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID) {
+               ret = 1;
+               goto end;
+       }
+
+       ok(expect == value, "Expected field type %s, got %s",
+                       field_value_type_to_str(expect),
+                       field_value_type_to_str(value));
+
+       ret = expect != value;
+
+end:
+       return ret;
+}
+
+/*
+ * Validate unsigned captured field against the iteration number.
+ */
+static int validate_unsigned_int_field(
+               const struct lttng_event_field_value *event_field,
+               unsigned int expected_value)
+{
+       int ret;
+       uint64_t value;
+       enum lttng_event_field_value_status status;
+
+       ret = validate_type(
+                       event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_unsigned_int_get_value(
+                       event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
+                               (int) status);
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == (uint64_t) expected_value,
+                       "Expected unsigned integer value %u, got %" PRIu64,
+                       expected_value, value);
+
+       ret = value != (uint64_t) expected_value;
+
+end:
+       return ret;
+}
+
+/*
+ * Validate signed captured field.
+ */
+static int validate_signed_int_field(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       const int64_t expected = -1;
+       int64_t value;
+       enum lttng_event_field_value_status status;
+
+       /* Unused. */
+       (void) iteration;
+
+       ret = validate_type(
+                       event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_signed_int_get_value(
+                       event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_signed_int_get_value returned an error: status = %d",
+                               (int) status);
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == expected,
+                       "Expected signed integer value %" PRId64
+                       ", got %" PRId64,
+                       expected, value);
+
+       ret = value != expected;
+
+end:
+
+       return ret;
+}
+
+/*
+ * Validate array of unsigned int.
+ */
+static int validate_array_unsigned_int_field(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       const unsigned int expected = 3;
+       unsigned int i, count;
+
+       /* Unused. */
+       (void) iteration;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_array_get_length(event_field, &count);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_array_get_length");
+               ret = 1;
+               goto end;
+       }
+
+       ok(count == expected, "Expected %d subelements, got %d", expected,
+                       count);
+       if (count != expected) {
+               ret = 1;
+               goto end;
+       }
+
+       for (i = 1; i < count + 1; i++) {
+               const struct lttng_event_field_value *value;
+
+               status = lttng_event_field_value_array_get_element_at_index(
+                               event_field, i - 1, &value);
+               if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
+                                       (int) status);
+                       ret = 1;
+                       goto end;
+               }
+
+               ret = validate_unsigned_int_field(value, i);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
+end:
+
+       return ret;
+}
+
+static int validate_array_unsigned_int_field_at_index(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       const uint64_t expected_value = 2;
+       enum lttng_event_field_value_status status;
+       uint64_t value;
+
+       /* Unused. */
+       (void) iteration;
+
+       ret = validate_type(
+                       event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_unsigned_int_get_value(
+                       event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
+                               (int) status);
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == expected_value,
+                       "Expected unsigned integer value %u, got %" PRIu64,
+                       expected_value, value);
+
+       ret = 0;
+end:
+       return ret;
+}
+
+/*
+ * Validate sequence for a string (seqfield1):
+ *
+ * Value: "test" encoded in UTF-8: [116, 101, 115, 116]
+ */
+static int validate_seqfield1(const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       unsigned int i, count;
+       const unsigned int expect[] = {116, 101, 115, 116};
+       const size_t array_count = sizeof(expect) / sizeof(*expect);
+
+       /* Unused. */
+       (void) iteration;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_array_get_length(event_field, &count);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_array_get_length returned an error: status = %d",
+                               (int) status);
+               ret = 1;
+               goto end;
+       }
+
+       ok(count == array_count, "Expected %zu array sub-elements, got %d",
+                       array_count, count);
+       if (count != array_count) {
+               ret = 1;
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_event_field_value *value;
+
+               status = lttng_event_field_value_array_get_element_at_index(
+                               event_field, i, &value);
+               if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
+                                       (int) status);
+                       ret = 1;
+                       goto end;
+               }
+
+               ret = validate_unsigned_int_field(value, expect[i]);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
+end:
+       return ret;
+}
+
+static int validate_string(
+               const struct lttng_event_field_value *event_field,
+               const char *expect)
+{
+       int ret;
+       const char *value = NULL;
+       enum lttng_event_field_value_status status;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_STRING);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_string_get_value(event_field, &value);
+       if (!value) {
+               fail("lttng_event_field_value_array_get_length returned an error: status = %d",
+                               (int) status);
+               ret = 1;
+               goto end;
+       }
+
+       ok(!strcmp(value, expect), "Expected string value \"%s\", got \"%s\"",
+                       expect, value);
+
+       ret = 0;
+end:
+
+       return ret;
+}
+
+/*
+ * Validate string. Expected value is "test".
+ */
+static int validate_string_test(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       const char * const expect = "test";
+
+       /* Unused. */
+       (void) iteration;
+
+       return validate_string(event_field, expect);
+}
+
+/*
+ * Validate escaped string. Expected value is "\*".
+ */
+static int validate_string_escaped(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       const char * const expect = "\\*";
+
+       /* Unused. */
+       (void) iteration;
+
+       return validate_string(event_field, expect);
+}
+
+/*
+ * Validate real field.
+ */
+static int validate_real(
+               const struct lttng_event_field_value *event_field,
+               double expect)
+{
+       int ret;
+       double value;
+       enum lttng_event_field_value_status status;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_REAL);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_real_get_value(event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_real_get_value returned an error: status = %d",
+                               (int) status);
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == expect, "Expected real value %f, got %f", expect, value);
+       ret = value != expect;
+end:
+       return ret;
+}
+
+/*
+ * Validate floatfield.
+ */
+static int validate_floatfield(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       const double expect = 2222.0;
+
+       /* Unused. */
+       (void) iteration;
+
+       return validate_real(event_field, expect);
+}
+
+/*
+ * Validate doublefield.
+ */
+static int validate_doublefield(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       const double expect = 2.0;
+
+       /* Unused. */
+       (void) iteration;
+
+       return validate_real(event_field, expect);
+}
+
+/*
+ * Validate enum0: enum0 = ( "AUTO: EXPECT 0" : container = 0 )
+ */
+static int validate_enum0(const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       uint64_t value;
+       const uint64_t expected_value = 0;
+
+       /* Unused. */
+       (void) iteration;
+
+       ret = validate_type(event_field,
+                       LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_unsigned_int_get_value(
+                       event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
+                               (int) status);
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == expected_value,
+                       "Expected enum value %" PRIu64 ", got %" PRIu64,
+                       expected_value, value);
+
+end:
+       return ret;
+}
+
+/*
+ * Validate enumnegative: enumnegative = ( "AUTO: EXPECT 0" : container = 0 )
+ *
+ * We expect 2 labels here.
+ */
+static int validate_enumnegative(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       int64_t value;
+       const int64_t expected_value = -1;
+
+       /* Unused. */
+       (void) iteration;
+
+       ret = validate_type(event_field,
+                       LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_signed_int_get_value(
+                       event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value");
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == expected_value,
+                       "Expected enum value %" PRId64 ", got %" PRId64,
+                       expected_value, value);
+
+end:
+       return ret;
+}
+
+static int validate_context_procname_ust(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       /* Unused. */
+       (void) iteration;
+       return validate_string(event_field, "gen-ust-events");
+}
+
+static int validate_context_procname_kernel(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       /* Unused. */
+       (void) iteration;
+       return validate_string(event_field, "echo");
+}
+
+struct capture_base_field_tuple test_capture_base_fields[] = {
+       { "DOESNOTEXIST", FIELD_TYPE_PAYLOAD, false, false, NULL, NULL },
+       { "intfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
+       { "longfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
+       { "signedfield", FIELD_TYPE_PAYLOAD, true, true, validate_signed_int_field, validate_signed_int_field },
+       { "arrfield1", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+       { "arrfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
+       { "arrfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+       { "seqfield1", FIELD_TYPE_PAYLOAD, true, true, validate_seqfield1, validate_seqfield1 },
+       { "seqfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
+       { "seqfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+       { "seqfield4", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+       { "arrfield1[1]", FIELD_TYPE_ARRAY_FIELD, true, true, validate_array_unsigned_int_field_at_index, validate_array_unsigned_int_field_at_index },
+       { "stringfield", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
+       { "stringfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_escaped, validate_string_escaped },
+       { "floatfield", FIELD_TYPE_PAYLOAD, true, false, validate_floatfield, validate_floatfield },
+       { "doublefield", FIELD_TYPE_PAYLOAD, true, false, validate_doublefield, validate_doublefield },
+       { "enum0", FIELD_TYPE_PAYLOAD, true, true, validate_enum0, validate_enum0 },
+       { "enumnegative", FIELD_TYPE_PAYLOAD, true, true, validate_enumnegative, validate_enumnegative },
+       { "$ctx.procname", FIELD_TYPE_CONTEXT, true, true, validate_context_procname_ust, validate_context_procname_kernel },
+};
+
+static const char *get_notification_trigger_name(
+               struct lttng_notification *notification)
+{
+       const char *trigger_name = NULL;
+       enum lttng_trigger_status trigger_status;
+       const struct lttng_trigger *trigger;
+
+       trigger = lttng_notification_get_trigger(notification);
+       if (!trigger) {
+               fail("Failed to get trigger from notification");
+               goto end;
+       }
+
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       switch (trigger_status) {
+       case LTTNG_TRIGGER_STATUS_OK:
+               break;
+       case LTTNG_TRIGGER_STATUS_UNSET:
+               trigger_name = "(anonymous)";
+               break;
+       default:
+               fail("Failed to get name from notification's trigger");
+               goto end;
+       }
+
+end:
+       return trigger_name;
+}
+
+static int validator_notification_trigger_name(
+               struct lttng_notification *notification,
+               const char *trigger_name)
+{
+       int ret;
+       bool name_is_equal;
+       const char *name;
+
+       LTTNG_ASSERT(notification);
+       LTTNG_ASSERT(trigger_name);
+
+       name = get_notification_trigger_name(notification);
+       if (name == NULL) {
+               ret = 1;
+               goto end;
+       }
+
+       name_is_equal = (strcmp(trigger_name, name) == 0);
+       ok(name_is_equal, "Expected trigger name: %s got %s", trigger_name,
+                       name);
+
+       ret = !name_is_equal;
+
+end:
+       return ret;
+}
+
+static
+void wait_on_file(const char *path, bool file_exist)
+{
+       if (!path) {
+               return;
+       }
+       for (;;) {
+               int ret;
+               struct stat buf;
+
+               ret = stat(path, &buf);
+               if (ret == -1 && errno == ENOENT) {
+                       if (file_exist) {
+                               /*
+                                * The file does not exist. wait a bit and
+                                * continue looping until it does.
+                                */
+                               (void) poll(NULL, 0, 10);
+                               continue;
+                       }
+
+                       /*
+                        * File does not exist and the exit condition we want.
+                        * Break from the loop and return.
+                        */
+                       break;
+               }
+               if (ret) {
+                       perror("stat");
+                       exit(EXIT_FAILURE);
+               }
+               /*
+                * stat() returned 0, so the file exists. break now only if
+                * that's the exit condition we want.
+                */
+               if (file_exist) {
+                       break;
+               }
+       }
+}
+
+static
+int write_pipe(const char *path, uint8_t data)
+{
+       int ret = 0;
+       int fd = 0;
+
+       fd = open(path, O_WRONLY | O_NONBLOCK);
+       if (fd < 0) {
+               perror("Could not open consumer control named pipe");
+               goto end;
+       }
+
+       ret = write(fd, &data , sizeof(data));
+       if (ret < 1) {
+               perror("Named pipe write failed");
+               if (close(fd)) {
+                       perror("Named pipe close failed");
+               }
+               ret = -1;
+               goto end;
+       }
+
+       ret = close(fd);
+       if (ret < 0) {
+               perror("Name pipe closing failed");
+               ret = -1;
+               goto end;
+       }
+end:
+       return ret;
+}
+
+static
+int stop_consumer(const char **argv)
+{
+       int ret = 0, i;
+
+       for (i = named_pipe_args_start; i < nb_args; i++) {
+               ret = write_pipe(argv[i], 49);
+       }
+       return ret;
+}
+
+static
+int resume_consumer(const char **argv)
+{
+       int ret = 0, i;
+
+       for (i = named_pipe_args_start; i < nb_args; i++) {
+               ret = write_pipe(argv[i], 0);
+       }
+       return ret;
+}
+
+static
+int suspend_application(void)
+{
+       int ret;
+       struct stat buf;
+
+       if (!stat(app_state_file, &buf)) {
+               fail("App is already in a suspended state.");
+               ret = -1;
+               goto error;
+       }
+
+       /*
+        * Send SIGUSR1 to application instructing it to bypass tracepoint.
+        */
+       LTTNG_ASSERT(app_pid > 1);
+
+       ret = kill(app_pid, SIGUSR1);
+       if (ret) {
+               fail("SIGUSR1 failed. errno %d", errno);
+               ret = -1;
+               goto error;
+       }
+
+       wait_on_file(app_state_file, true);
+
+error:
+       return ret;
+
+}
+
+static
+int resume_application(void)
+{
+       int ret;
+       struct stat buf;
+
+       ret = stat(app_state_file, &buf);
+       if (ret == -1 && errno == ENOENT) {
+               fail("State file does not exist");
+               goto error;
+       }
+       if (ret) {
+               perror("stat");
+               goto error;
+       }
+
+       LTTNG_ASSERT(app_pid > 1);
+
+       ret = kill(app_pid, SIGUSR1);
+       if (ret) {
+               fail("SIGUSR1 failed. errno %d", errno);
+               ret = -1;
+               goto error;
+       }
+
+       wait_on_file(app_state_file, false);
+
+error:
+       return ret;
+
+}
+
+
+static
+void test_triggers_buffer_usage_condition(const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type,
+               enum lttng_condition_type condition_type)
+{
+       unsigned int test_vector_size = 5, i;
+       enum lttng_condition_status condition_status;
+       struct lttng_action *action;
+
+       /* Set-up */
+       action = lttng_action_notify_create();
+       if (!action) {
+               fail("Setup error on action creation");
+               goto end;
+       }
+
+       /* Test lttng_register_trigger with null value */
+       ok(lttng_register_trigger(NULL) == -LTTNG_ERR_INVALID, "Registering a NULL trigger fails as expected");
+
+       /* Test: register a trigger */
+
+       for (i = 0; i < pow(2,test_vector_size); i++) {
+               int loop_ret = 0;
+               char *test_tuple_string = NULL;
+               unsigned int mask_position = 0;
+               bool session_name_set = false;
+               bool channel_name_set = false;
+               bool threshold_ratio_set = false;
+               bool threshold_byte_set = false;
+               bool domain_type_set = false;
+
+               struct lttng_trigger *trigger = NULL;
+               struct lttng_condition *condition = NULL;
+
+               /* Create base condition */
+               switch (condition_type) {
+               case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+                       condition = lttng_condition_buffer_usage_low_create();
+                       break;
+               case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+                       condition = lttng_condition_buffer_usage_high_create();
+                       break;
+               default:
+                       loop_ret = 1;
+                       goto loop_end;
+               }
+
+               if (!condition) {
+                       loop_ret = 1;
+                       goto loop_end;
+
+               }
+
+               /* Prepare the condition for trigger registration test */
+
+               /* Set session name */
+               if ((1 << mask_position) & i) {
+                       condition_status = lttng_condition_buffer_usage_set_session_name(
+                                       condition, session_name);
+                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+                               loop_ret = 1;
+                               goto loop_end;
+                       }
+                       session_name_set = true;
+               }
+               mask_position++;
+
+               /* Set channel name */
+               if ((1 << mask_position) & i) {
+                       condition_status = lttng_condition_buffer_usage_set_channel_name(
+                                       condition, channel_name);
+                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+                               loop_ret = 1;
+                               goto loop_end;
+                       }
+                       channel_name_set = true;
+               }
+               mask_position++;
+
+               /* Set threshold ratio */
+               if ((1 << mask_position) & i) {
+                       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+                                       condition, 0.0);
+                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+                               loop_ret = 1;
+                               goto loop_end;
+                       }
+                       threshold_ratio_set = true;
+               }
+               mask_position++;
+
+               /* Set threshold byte */
+               if ((1 << mask_position) & i) {
+                       condition_status = lttng_condition_buffer_usage_set_threshold(
+                                       condition, 0);
+                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+                               loop_ret = 1;
+                               goto loop_end;
+                       }
+                       threshold_byte_set = true;
+               }
+               mask_position++;
+
+               /* Set domain type */
+               if ((1 << mask_position) & i) {
+                       condition_status = lttng_condition_buffer_usage_set_domain_type(
+                                       condition, LTTNG_DOMAIN_UST);
+                       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+                               loop_ret = 1;
+                               goto loop_end;
+                       }
+                       domain_type_set = true;
+               }
+
+               /* Safety check */
+               if (mask_position != test_vector_size -1) {
+                       LTTNG_ASSERT("Logic error for test vector generation");
+               }
+
+               loop_ret = asprintf(&test_tuple_string, "session name %s, channel name %s, threshold ratio %s, threshold byte %s, domain type %s",
+                               session_name_set ? "set" : "unset",
+                               channel_name_set ? "set" : "unset",
+                               threshold_ratio_set ? "set" : "unset",
+                               threshold_byte_set ? "set" : "unset",
+                               domain_type_set? "set" : "unset");
+               if (!test_tuple_string || loop_ret < 0) {
+                       loop_ret = 1;
+                       goto loop_end;
+               }
+
+               /* Create trigger */
+               trigger = lttng_trigger_create(condition, action);
+               if (!trigger) {
+                       loop_ret = 1;
+                       goto loop_end;
+               }
+
+               loop_ret = lttng_register_trigger(trigger);
+
+loop_end:
+               if (loop_ret == 1) {
+                       fail("Setup error occurred for tuple: %s", test_tuple_string);
+                       goto loop_cleanup;
+               }
+
+               /* This combination happens three times */
+               if (session_name_set && channel_name_set
+                               && (threshold_ratio_set || threshold_byte_set)
+                               && domain_type_set) {
+                       ok(loop_ret == 0, "Trigger is registered: %s", test_tuple_string);
+
+                       /*
+                        * Test that a trigger cannot be registered
+                        * multiple time.
+                        */
+                       loop_ret = lttng_register_trigger(trigger);
+                       ok(loop_ret == -LTTNG_ERR_TRIGGER_EXISTS, "Re-register trigger fails as expected: %s", test_tuple_string);
+
+                       /* Test that a trigger can be unregistered */
+                       loop_ret = lttng_unregister_trigger(trigger);
+                       ok(loop_ret == 0, "Unregister trigger: %s", test_tuple_string);
+
+                       /*
+                        * Test that unregistration of a non-previously
+                        * registered trigger fail.
+                        */
+                       loop_ret = lttng_unregister_trigger(trigger);
+                       ok(loop_ret == -LTTNG_ERR_TRIGGER_NOT_FOUND, "Unregister of a non-registered trigger fails as expected: %s", test_tuple_string);
+               } else {
+                       ok(loop_ret == -LTTNG_ERR_INVALID_TRIGGER, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string);
+               }
+
+loop_cleanup:
+               free(test_tuple_string);
+               lttng_trigger_destroy(trigger);
+               lttng_condition_destroy(condition);
+       }
+
+end:
+       lttng_action_destroy(action);
+}
+
+static
+void wait_data_pending(const char *session_name)
+{
+       int ret;
+
+       do {
+               ret = lttng_data_pending(session_name);
+               LTTNG_ASSERT(ret >= 0);
+       } while (ret != 0);
+}
+
+static
+int setup_buffer_usage_condition(struct lttng_condition *condition,
+               const char *condition_name,
+               const char *session_name,
+               const char *channel_name,
+               const enum lttng_domain_type domain_type)
+{
+       enum lttng_condition_status condition_status;
+       int ret = 0;
+
+       condition_status = lttng_condition_buffer_usage_set_session_name(
+                       condition, session_name);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               fail("Failed to set session name on creation of condition `%s`",
+                               condition_name);
+               ret = -1;
+               goto end;
+       }
+
+       condition_status = lttng_condition_buffer_usage_set_channel_name(
+                       condition, channel_name);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               fail("Failed to set channel name on creation of condition `%s`",
+                               condition_name);
+               ret = -1;
+               goto end;
+       }
+
+       condition_status = lttng_condition_buffer_usage_set_domain_type(
+                       condition, domain_type);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               fail("Failed to set domain type on creation of condition `%s`",
+                               condition_name);
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+void test_invalid_channel_subscription(
+               const enum lttng_domain_type domain_type)
+{
+       enum lttng_condition_status condition_status;
+       enum lttng_notification_channel_status nc_status;
+       struct lttng_condition *dummy_condition = NULL;
+       struct lttng_condition *dummy_invalid_condition = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       int ret = 0;
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+       if (!notification_channel) {
+               goto end;
+       }
+
+       /*
+        * Create a dummy, empty (thus invalid) condition to test error paths.
+        */
+       dummy_invalid_condition = lttng_condition_buffer_usage_low_create();
+       if (!dummy_invalid_condition) {
+               fail("Setup error on condition creation");
+               goto end;
+       }
+
+       /*
+        * Test subscription and unsubscription of an invalid condition to/from
+        * a channel.
+        */
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, dummy_invalid_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+                       "Subscribing to an invalid condition");
+
+       nc_status = lttng_notification_channel_unsubscribe(
+                       notification_channel, dummy_invalid_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+                       "Unsubscribing from an invalid condition");
+
+       /* Create a valid dummy condition with a ratio of 0.5 */
+       dummy_condition = lttng_condition_buffer_usage_low_create();
+       if (!dummy_condition) {
+               fail("Setup error on dummy_condition creation");
+               goto end;
+       }
+
+       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+                       dummy_condition, 0.5);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               fail("Setup error on condition creation");
+               goto end;
+       }
+
+       ret = setup_buffer_usage_condition(dummy_condition, "dummy_condition",
+                       "dummy_session", "dummy_channel", domain_type);
+       if (ret) {
+               fail("Setup error on dummy condition creation");
+               goto end;
+       }
+
+       /*
+        * Test subscription and unsubscription to/from a channel with invalid
+        * parameters.
+        */
+       nc_status = lttng_notification_channel_subscribe(NULL, NULL);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+                       "Notification channel subscription is invalid: NULL, NULL");
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, NULL);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+                       "Notification channel subscription is invalid: NON-NULL, NULL");
+
+       nc_status = lttng_notification_channel_subscribe(NULL, dummy_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+                       "Notification channel subscription is invalid: NULL, NON-NULL");
+
+       nc_status = lttng_notification_channel_unsubscribe(
+                       notification_channel, dummy_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION,
+                       "Unsubscribing from a valid unknown condition");
+
+end:
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_condition_destroy(dummy_invalid_condition);
+       lttng_condition_destroy(dummy_condition);
+       return;
+}
+
+enum buffer_usage_type {
+       BUFFER_USAGE_TYPE_LOW,
+       BUFFER_USAGE_TYPE_HIGH,
+};
+
+static int register_buffer_usage_notify_trigger(const char *session_name,
+               const char *channel_name,
+               const enum lttng_domain_type domain_type,
+               enum buffer_usage_type buffer_usage_type,
+               double ratio,
+               struct lttng_condition **condition,
+               struct lttng_action **action,
+               struct lttng_trigger **trigger)
+{
+       enum lttng_condition_status condition_status;
+       struct lttng_action *tmp_action = NULL;
+       struct lttng_condition *tmp_condition = NULL;
+       struct lttng_trigger *tmp_trigger = NULL;
+       int ret = 0;
+
+       /* Set-up */
+       tmp_action = lttng_action_notify_create();
+       if (!action) {
+               fail("Setup error on action creation");
+               ret = -1;
+               goto error;
+       }
+
+       if (buffer_usage_type == BUFFER_USAGE_TYPE_LOW) {
+               tmp_condition = lttng_condition_buffer_usage_low_create();
+       } else {
+               tmp_condition = lttng_condition_buffer_usage_high_create();
+       }
+
+       if (!tmp_condition) {
+               fail("Setup error on condition creation");
+               ret = -1;
+               goto error;
+       }
+
+       /* Set the buffer usage threashold */
+       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+                       tmp_condition, ratio);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               fail("Setup error on condition creation");
+               ret = -1;
+               goto error;
+       }
+
+       ret = setup_buffer_usage_condition(tmp_condition, "condition_name",
+                       session_name, channel_name, domain_type);
+       if (ret) {
+               fail("Setup error on condition creation");
+               ret = -1;
+               goto error;
+       }
+
+       /* Register the trigger for condition. */
+       tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
+       if (!tmp_trigger) {
+               fail("Setup error on trigger creation");
+               ret = -1;
+               goto error;
+       }
+
+       ret = lttng_register_trigger(tmp_trigger);
+       if (ret) {
+               fail("Setup error on trigger registration");
+               ret = -1;
+               goto error;
+       }
+
+       *condition = tmp_condition;
+       *trigger = tmp_trigger;
+       *action = tmp_action;
+       goto end;
+
+error:
+       lttng_action_destroy(tmp_action);
+       lttng_condition_destroy(tmp_condition);
+       lttng_trigger_destroy(tmp_trigger);
+
+end:
+       return ret;
+}
+
+static void test_subscription_twice(const char *session_name,
+               const char *channel_name,
+               const enum lttng_domain_type domain_type)
+{
+       int ret = 0;
+       enum lttng_notification_channel_status nc_status;
+
+       struct lttng_action *action = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_trigger *trigger = NULL;
+
+       struct lttng_condition *condition = NULL;
+
+       ret = register_buffer_usage_notify_trigger(session_name, channel_name,
+                       domain_type, BUFFER_USAGE_TYPE_LOW, 0.99, &condition,
+                       &action, &trigger);
+       if (ret) {
+               fail("Setup error on trigger registration in %s()",
+                               __FUNCTION__);
+               goto end;
+       }
+
+       /* Begin testing. */
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+       if (!notification_channel) {
+               goto end;
+       }
+
+       /* Subscribe a valid condition. */
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to condition");
+
+       /* Subscribing again should fail. */
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED,
+                       "Subscribe to a condition for which subscription was already done");
+
+end:
+       ret = lttng_unregister_trigger(trigger);
+       if (ret) {
+               fail("Failed to unregister trigger in %s()", __FUNCTION__);
+       }
+
+       lttng_trigger_destroy(trigger);
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_action_destroy(action);
+       lttng_condition_destroy(condition);
+}
+
+static void test_buffer_usage_notification_channel(const char *session_name,
+               const char *channel_name,
+               const enum lttng_domain_type domain_type,
+               const char **argv)
+{
+       int ret = 0;
+       enum lttng_notification_channel_status nc_status;
+
+       struct lttng_action *low_action = NULL;
+       struct lttng_action *high_action = NULL;
+       struct lttng_notification *notification = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_trigger *low_trigger = NULL;
+       struct lttng_trigger *high_trigger = NULL;
+
+       struct lttng_condition *low_condition = NULL;
+       struct lttng_condition *high_condition = NULL;
+
+       const double low_ratio = 0.0;
+       const double high_ratio = 0.90;
+
+       ret = register_buffer_usage_notify_trigger(session_name, channel_name,
+                       domain_type, BUFFER_USAGE_TYPE_LOW, low_ratio,
+                       &low_condition, &low_action, &low_trigger);
+       if (ret) {
+               fail("Setup error on low trigger registration");
+               goto end;
+       }
+
+       ret = register_buffer_usage_notify_trigger(session_name, channel_name,
+                       domain_type, BUFFER_USAGE_TYPE_HIGH, high_ratio,
+                       &high_condition, &high_action, &high_trigger);
+       if (ret) {
+               fail("Setup error on high trigger registration");
+               goto end;
+       }
+
+       /* Begin testing */
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+       if (!notification_channel) {
+               goto end;
+       }
+
+       /* Subscribe a valid low condition */
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, low_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to low condition");
+
+       /* Subscribe a valid high condition */
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, high_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to high condition");
+
+       resume_application();
+
+       /* Wait for notification to happen */
+       stop_consumer(argv);
+       lttng_start_tracing(session_name);
+
+       /* Wait for high notification */
+       do {
+               nc_status = lttng_notification_channel_get_next_notification(
+                               notification_channel, &notification);
+       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+                                       lttng_condition_get_type(lttng_notification_get_condition(
+                                                       notification)) ==
+                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
+                       "High notification received after intermediary communication");
+       lttng_notification_destroy(notification);
+       notification = NULL;
+
+       suspend_application();
+       lttng_stop_tracing_no_wait(session_name);
+       resume_consumer(argv);
+       wait_data_pending(session_name);
+
+       /*
+        * Test that communication still work even if there is notification
+        * waiting for consumption.
+        */
+
+       nc_status = lttng_notification_channel_unsubscribe(
+                       notification_channel, low_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Unsubscribe with pending notification");
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, low_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe with pending notification");
+
+       do {
+               nc_status = lttng_notification_channel_get_next_notification(
+                               notification_channel, &notification);
+       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+                                       lttng_condition_get_type(lttng_notification_get_condition(
+                                                       notification)) ==
+                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
+                       "Low notification received after intermediary communication");
+       lttng_notification_destroy(notification);
+       notification = NULL;
+
+       /* Stop consumer to force a high notification */
+       stop_consumer(argv);
+       resume_application();
+       lttng_start_tracing(session_name);
+
+       do {
+               nc_status = lttng_notification_channel_get_next_notification(
+                               notification_channel, &notification);
+       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+                                       lttng_condition_get_type(lttng_notification_get_condition(
+                                                       notification)) ==
+                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
+                       "High notification received after intermediary communication");
+       lttng_notification_destroy(notification);
+       notification = NULL;
+
+       suspend_application();
+       lttng_stop_tracing_no_wait(session_name);
+       resume_consumer(argv);
+       wait_data_pending(session_name);
+
+       do {
+               nc_status = lttng_notification_channel_get_next_notification(
+                               notification_channel, &notification);
+       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+                                       lttng_condition_get_type(lttng_notification_get_condition(
+                                                       notification)) ==
+                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
+                       "Low notification received after re-subscription");
+       lttng_notification_destroy(notification);
+       notification = NULL;
+
+       stop_consumer(argv);
+       resume_application();
+       /* Stop consumer to force a high notification */
+       lttng_start_tracing(session_name);
+
+       do {
+               nc_status = lttng_notification_channel_get_next_notification(
+                               notification_channel, &notification);
+       } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+                                       lttng_condition_get_type(lttng_notification_get_condition(
+                                                       notification)) ==
+                                                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
+                       "High notification");
+       lttng_notification_destroy(notification);
+       notification = NULL;
+
+       suspend_application();
+
+       /* Resume consumer to allow event consumption */
+       lttng_stop_tracing_no_wait(session_name);
+       resume_consumer(argv);
+       wait_data_pending(session_name);
+
+       nc_status = lttng_notification_channel_unsubscribe(
+                       notification_channel, low_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Unsubscribe low condition with pending notification");
+
+       nc_status = lttng_notification_channel_unsubscribe(
+                       notification_channel, high_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Unsubscribe high condition with pending notification");
+
+end:
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_trigger_destroy(low_trigger);
+       lttng_trigger_destroy(high_trigger);
+       lttng_action_destroy(low_action);
+       lttng_action_destroy(high_action);
+       lttng_condition_destroy(low_condition);
+       lttng_condition_destroy(high_condition);
+}
+
+static void create_tracepoint_event_rule_trigger(const char *event_pattern,
+               const char *trigger_name,
+               const char *filter,
+               unsigned int exclusion_count,
+               const char * const *exclusions,
+               enum lttng_domain_type domain_type,
+               condition_capture_desc_cb capture_desc_cb,
+               struct lttng_condition **condition,
+               struct lttng_trigger **trigger)
+{
+       typedef struct lttng_event_rule *(*event_rule_create)(void);
+       typedef enum lttng_event_rule_status (
+                       *event_rule_set_name_pattern)(
+                       struct lttng_event_rule *rule,
+                       const char *pattern);
+       typedef enum lttng_event_rule_status (*event_rule_set_filter)(
+                       struct lttng_event_rule *rule,
+                       const char *expression);
+       typedef enum lttng_event_rule_status (
+                       *event_rule_add_name_pattern_exclusion)(
+                       struct lttng_event_rule * rule, const char *exclusion);
+
+       enum lttng_event_rule_status event_rule_status;
+       struct lttng_action *tmp_action = NULL;
+       struct lttng_event_rule *event_rule = NULL;
+       struct lttng_condition *tmp_condition = NULL;
+       struct lttng_trigger *tmp_trigger = NULL;
+       int ret;
+       enum lttng_error_code ret_code;
+       event_rule_create create;
+       event_rule_set_name_pattern set_name_pattern;
+       event_rule_set_filter set_filter;
+       event_rule_add_name_pattern_exclusion add_name_pattern_exclusion;
+
+       LTTNG_ASSERT(event_pattern);
+       LTTNG_ASSERT(trigger_name);
+       LTTNG_ASSERT(condition);
+       LTTNG_ASSERT(trigger);
+
+       /* Set the function pointers based on the domain type. */
+       switch (domain_type) {
+       case LTTNG_DOMAIN_UST:
+               create = lttng_event_rule_user_tracepoint_create;
+               set_name_pattern = lttng_event_rule_user_tracepoint_set_name_pattern;
+               set_filter = lttng_event_rule_user_tracepoint_set_filter;
+               add_name_pattern_exclusion = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion;
+               break;
+       case LTTNG_DOMAIN_KERNEL:
+               create = lttng_event_rule_kernel_tracepoint_create;
+               set_name_pattern = lttng_event_rule_kernel_tracepoint_set_name_pattern;
+               set_filter = lttng_event_rule_kernel_tracepoint_set_filter;
+               add_name_pattern_exclusion = NULL;
+               break;
+       default:
+               abort();
+               break;
+       }
+
+       event_rule = create();
+       ok(event_rule, "Tracepoint event rule object creation");
+
+       event_rule_status = set_name_pattern(event_rule, event_pattern);
+       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting tracepoint event rule pattern: '%s'",
+                       event_pattern);
+
+       if (filter) {
+               event_rule_status = set_filter(event_rule, filter);
+               ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+                               "Setting tracepoint event rule filter: '%s'",
+                               filter);
+       }
+
+       if (exclusions) {
+               int i;
+               bool success = true;
+
+               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
+               LTTNG_ASSERT(add_name_pattern_exclusion != NULL);
+               LTTNG_ASSERT(exclusion_count > 0);
+
+               for (i = 0; i < exclusion_count; i++) {
+                       event_rule_status = add_name_pattern_exclusion(
+                                       event_rule, exclusions[i]);
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               fail("Setting tracepoint event rule exclusion '%s'.",
+                                               exclusions[i]);
+                               success = false;
+                       }
+               }
+
+               ok(success, "Setting tracepoint event rule exclusions");
+       }
+
+       tmp_condition = lttng_condition_event_rule_matches_create(event_rule);
+       ok(tmp_condition, "Condition event rule object creation");
+
+       if (capture_desc_cb) {
+               ret = capture_desc_cb(tmp_condition);
+               if (ret) {
+                       fail("Failed to generate the condition capture descriptor");
+                       abort();
+               }
+       }
+
+       tmp_action = lttng_action_notify_create();
+       ok(tmp_action, "Action event rule object creation");
+
+       tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
+       ok(tmp_trigger, "Trigger object creation %s", trigger_name);
+
+       ret_code = lttng_register_trigger_with_name(tmp_trigger, trigger_name);
+       ok(ret_code == LTTNG_OK, "Trigger registration %s", trigger_name);
+
+       lttng_event_rule_destroy(event_rule);
+
+       *condition = tmp_condition;
+       *trigger = tmp_trigger;
+
+       return;
+}
+
+static struct lttng_notification *get_next_notification(
+               struct lttng_notification_channel *notification_channel)
+{
+       struct lttng_notification *local_notification = NULL;
+       enum lttng_notification_channel_status status;
+
+       /* Receive the next notification. */
+       status = lttng_notification_channel_get_next_notification(
+                       notification_channel, &local_notification);
+
+       switch (status) {
+       case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
+               break;
+       case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
+               fail("Notifications have been dropped");
+               local_notification = NULL;
+               break;
+       default:
+               /* Unhandled conditions / errors. */
+               fail("Failed to get next notification (unknown notification channel status): status = %d",
+                               (int) status);
+               local_notification = NULL;
+               break;
+       }
+
+       return local_notification;
+}
+
+static void test_tracepoint_event_rule_notification(
+               enum lttng_domain_type domain_type)
+{
+       int i;
+       int ret;
+       const int notification_count = 3;
+       enum lttng_notification_channel_status nc_status;
+       struct lttng_action *action = NULL;
+       struct lttng_condition *condition = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_trigger *trigger = NULL;
+       const char * const trigger_name = "my_precious";
+       const char *pattern;
+
+       if (domain_type == LTTNG_DOMAIN_UST) {
+               pattern = "tp:tptest";
+       } else {
+               pattern = "lttng_test_filter_event";
+       }
+
+       create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
+                       NULL, domain_type, NULL, &condition, &trigger);
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       resume_application();
+
+       /* Get notifications. */
+       for (i = 0; i < notification_count; i++) {
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+
+               ok(notification, "Received notification (%d/%d)", i + 1,
+                               notification_count);
+
+               /* Error. */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_name(notification, trigger_name);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       suspend_application();
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_unregister_trigger(trigger);
+       lttng_trigger_destroy(trigger);
+       lttng_action_destroy(action);
+       lttng_condition_destroy(condition);
+       return;
+}
+
+static void test_tracepoint_event_rule_notification_filter(
+               enum lttng_domain_type domain_type)
+{
+       int i;
+       const int notification_count = 3;
+       enum lttng_notification_channel_status nc_status;
+       struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
+       const char * const ctrl_trigger_name = "control_trigger";
+       const char * const trigger_name = "trigger";
+       const char *pattern;
+       int ctrl_count = 0, count = 0;
+
+       if (domain_type == LTTNG_DOMAIN_UST) {
+               pattern = "tp:tptest";
+       } else {
+               pattern = "lttng_test_filter_event";
+       }
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
+                       0, NULL, domain_type, NULL, &ctrl_condition, &ctrl_trigger);
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, ctrl_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       /*
+        * Attach a filter expression to get notification only if the
+        * `intfield` is even.
+        */
+       create_tracepoint_event_rule_trigger(pattern, trigger_name,
+                       "(intfield & 1) == 0", 0, NULL, domain_type, NULL, &condition,
+                       &trigger);
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       /*
+        * We registered 2 notifications triggers, one with a filter and one
+        * without (control). The one with a filter will only fired when the
+        * `intfield` is a multiple of 2. We should get two times as many
+        * control notifications as filter notifications.
+        */
+       resume_application();
+
+       /*
+        * Get 3 notifications. We should get 1 for the regular trigger (with
+        * the filter) and 2 from the control trigger. This works whatever
+        * the order we receive the notifications.
+        */
+       for (i = 0; i < notification_count; i++) {
+               const char *name;
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+
+               ok(notification, "Received notification (%d/%d)", i + 1,
+                               notification_count);
+
+               /* Error. */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               name = get_notification_trigger_name(notification);
+               if (name == NULL) {
+                       lttng_notification_destroy(notification);
+                       goto end;
+               }
+
+               if (strcmp(ctrl_trigger_name, name) == 0) {
+                       ctrl_count++;
+               } else if (strcmp(trigger_name, name) == 0) {
+                       count++;
+               }
+
+               lttng_notification_destroy(notification);
+       }
+
+       ok(ctrl_count / 2 == count,
+                       "Get twice as many control notif as of regular notif");
+
+end:
+       suspend_application();
+
+       lttng_unregister_trigger(trigger);
+       lttng_unregister_trigger(ctrl_trigger);
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_trigger_destroy(trigger);
+       lttng_trigger_destroy(ctrl_trigger);
+       lttng_condition_destroy(condition);
+       lttng_condition_destroy(ctrl_condition);
+}
+
+static void test_tracepoint_event_rule_notification_exclusion(
+               enum lttng_domain_type domain_type)
+{
+       enum lttng_notification_channel_status nc_status;
+       struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
+       int ctrl_count = 0, count = 0, i;
+       const int notification_count = 6;
+       const char * const ctrl_trigger_name = "control_exclusion_trigger";
+       const char * const trigger_name = "exclusion_trigger";
+       const char * const pattern = "tp:tptest*";
+       const char * const exclusions[] = {
+               "tp:tptest2",
+               "tp:tptest3",
+               "tp:tptest4",
+               "tp:tptest5"
+       };
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
+                       0, NULL, domain_type, NULL, &ctrl_condition,
+                       &ctrl_trigger);
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, ctrl_condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 4,
+                       exclusions, domain_type, NULL, &condition,
+                       &trigger);
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       /*
+        * We registered 2 notifications triggers, one with an exclusion and
+        * one without (control).
+        * - The trigger with an exclusion will fire once every iteration.
+        * - The trigger without an exclusion will fire 5 times every
+        *   iteration.
+        *
+        *   We should get 5 times as many notifications from the control
+        *   trigger.
+        */
+       resume_application();
+
+       /*
+        * Get 6 notifications. We should get 1 for the regular trigger (with
+        * the exclusion) and 5 from the control trigger. This works whatever
+        * the order we receive the notifications.
+        */
+       for (i = 0; i < notification_count; i++) {
+               const char *name;
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+
+               ok(notification, "Received notification (%d/%d)", i + 1,
+                               notification_count);
+
+               /* Error. */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               name = get_notification_trigger_name(notification);
+               if (name == NULL) {
+                       lttng_notification_destroy(notification);
+                       goto end;
+               }
+
+               if (strcmp(ctrl_trigger_name, name) == 0) {
+                       ctrl_count++;
+               } else if (strcmp(trigger_name, name) == 0) {
+                       count++;
+               }
+
+               lttng_notification_destroy(notification);
+       }
+
+       ok(ctrl_count / 5 == count,
+                       "Got 5 times as many control notif as of regular notif");
+
+end:
+       suspend_application();
+
+       lttng_unregister_trigger(trigger);
+       lttng_unregister_trigger(ctrl_trigger);
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_trigger_destroy(trigger);
+       lttng_trigger_destroy(ctrl_trigger);
+       lttng_condition_destroy(condition);
+       lttng_condition_destroy(ctrl_condition);
+       return;
+}
+
+static void test_kprobe_event_rule_notification(
+               enum lttng_domain_type domain_type)
+{
+       int i, ret;
+       enum lttng_error_code ret_code;
+       const int notification_count = 3;
+       enum lttng_notification_channel_status nc_status;
+       enum lttng_event_rule_status event_rule_status;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_condition *condition = NULL;
+       struct lttng_kernel_probe_location *location = NULL;
+       struct lttng_event_rule *event_rule = NULL;
+       struct lttng_action *action = NULL;
+       struct lttng_trigger *trigger = NULL;
+       const char * const trigger_name = "kprobe_trigger";
+       const char * const symbol_name = "lttng_test_filter_event_write";
+
+       action = lttng_action_notify_create();
+       if (!action) {
+               fail("Failed to create notify action");
+               goto end;
+       }
+
+       location = lttng_kernel_probe_location_symbol_create(symbol_name, 0);
+       if (!location) {
+               fail("Failed to create kernel probe location");
+               goto end;
+       }
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       event_rule = lttng_event_rule_kernel_kprobe_create(location);
+       ok(event_rule, "kprobe event rule object creation");
+
+       event_rule_status = lttng_event_rule_kernel_kprobe_set_event_name(
+                       event_rule, trigger_name);
+       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting kprobe event rule name: '%s'", trigger_name);
+
+       condition = lttng_condition_event_rule_matches_create(event_rule);
+       ok(condition, "Condition event rule object creation");
+
+       /* Register the trigger for condition. */
+       trigger = lttng_trigger_create(condition, action);
+       if (!trigger) {
+               fail("Failed to create trigger with kernel probe event rule condition and notify action");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to register trigger with kernel probe event rule condition and notify action");
+               goto end;
+       }
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       resume_application();
+
+       for (i = 0; i < notification_count; i++) {
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+
+               ok(notification, "Received notification (%d/%d)", i + 1,
+                               notification_count);
+
+               /* Error. */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_name(notification, trigger_name);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       suspend_application();
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_unregister_trigger(trigger);
+       lttng_trigger_destroy(trigger);
+       lttng_action_destroy(action);
+       lttng_event_rule_destroy(event_rule);
+       lttng_condition_destroy(condition);
+       lttng_kernel_probe_location_destroy(location);
+       return;
+}
+
+static void test_uprobe_event_rule_notification(
+               enum lttng_domain_type domain_type,
+               const char *testapp_path,
+               const char *test_symbol_name)
+{
+       int i, ret;
+       enum lttng_error_code ret_code;
+       const int notification_count = 3;
+       enum lttng_notification_channel_status nc_status;
+       enum lttng_event_rule_status event_rule_status;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_userspace_probe_location *probe_location = NULL;
+       struct lttng_userspace_probe_location_lookup_method *lookup_method =
+                       NULL;
+       struct lttng_condition *condition = NULL;
+       struct lttng_event_rule *event_rule = NULL;
+       struct lttng_action *action = NULL;
+       struct lttng_trigger *trigger = NULL;
+       const char * const trigger_name = "uprobe_trigger";
+
+       action = lttng_action_notify_create();
+       if (!action) {
+               fail("Failed to create notify action");
+               goto end;
+       }
+
+       lookup_method = lttng_userspace_probe_location_lookup_method_function_elf_create();
+       if (!lookup_method) {
+               fail("Setup error on userspace probe lookup method creation");
+               goto end;
+       }
+
+       probe_location = lttng_userspace_probe_location_function_create(
+                       testapp_path, test_symbol_name, lookup_method);
+       if (!probe_location) {
+               fail("Failed to create userspace probe location");
+               goto end;
+       }
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       event_rule = lttng_event_rule_kernel_uprobe_create(probe_location);
+       ok(event_rule, "kprobe event rule object creation");
+
+       event_rule_status = lttng_event_rule_kernel_uprobe_set_event_name(
+                       event_rule, trigger_name);
+       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting uprobe event rule name: '%s'", trigger_name);
+
+       condition = lttng_condition_event_rule_matches_create(event_rule);
+       ok(condition, "Condition event rule object creation");
+
+       /* Register the trigger for condition. */
+       trigger = lttng_trigger_create(condition, action);
+       if (!trigger) {
+               fail("Failed to create trigger with userspace probe event rule condition and notify action");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to register trigger with userspace probe event rule condition and notify action");
+               goto end;
+       }
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       resume_application();
+
+       for (i = 0; i < 3; i++) {
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+
+               ok(notification, "Received notification (%d/%d)", i + 1,
+                               notification_count);
+
+               /* Error. */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_name(notification, trigger_name);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       suspend_application();
+
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_unregister_trigger(trigger);
+       lttng_trigger_destroy(trigger);
+       lttng_action_destroy(action);
+       lttng_userspace_probe_location_destroy(probe_location);
+       lttng_event_rule_destroy(event_rule);
+       lttng_condition_destroy(condition);
+       return;
+}
+
+static void test_syscall_event_rule_notification(
+               enum lttng_domain_type domain_type)
+{
+       int i, ret;
+       enum lttng_error_code ret_code;
+       const int notification_count = 3;
+       enum lttng_notification_channel_status nc_status;
+       enum lttng_event_rule_status event_rule_status;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_condition *condition = NULL;
+       struct lttng_event_rule *event_rule = NULL;
+       struct lttng_action *action = NULL;
+       struct lttng_trigger *trigger = NULL;
+       const char * const trigger_name = "syscall_trigger";
+       const char * const syscall_name = "openat";
+
+       action = lttng_action_notify_create();
+       if (!action) {
+               fail("Failed to create notify action");
+               goto end;
+       }
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
+       ok(event_rule, "syscall event rule object creation");
+
+       event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
+                       event_rule, syscall_name);
+       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting syscall event rule pattern: '%s'", syscall_name);
+
+       condition = lttng_condition_event_rule_matches_create(event_rule);
+       ok(condition, "Condition syscall event rule object creation");
+
+       /* Register the trigger for condition. */
+       trigger = lttng_trigger_create(condition, action);
+       if (!trigger) {
+               fail("Failed to create trigger with syscall event rule condition and notify action");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to register trigger with syscall event rule condition and notify action");
+               goto end;
+       }
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       resume_application();
+
+       for (i = 0; i < notification_count; i++) {
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+
+               ok(notification, "Received notification (%d/%d)", i + 1,
+                               notification_count);
+
+               /* Error. */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_name(notification, trigger_name);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       suspend_application();
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_unregister_trigger(trigger);
+       lttng_trigger_destroy(trigger);
+       lttng_action_destroy(action);
+       lttng_condition_destroy(condition);
+       return;
+}
+
+static void test_syscall_event_rule_notification_filter(
+               enum lttng_domain_type domain_type)
+{
+       int i, ret;
+       enum lttng_error_code ret_code;
+       const int notification_count = 3;
+       enum lttng_notification_channel_status nc_status;
+       enum lttng_event_rule_status event_rule_status;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_condition *condition = NULL;
+       struct lttng_event_rule *event_rule = NULL;
+       struct lttng_action *action = NULL;
+       struct lttng_trigger *trigger = NULL;
+       const char * const trigger_name = "syscall_trigger";
+       const char * const syscall_name = "openat";
+       const char * const filter_pattern = "filename == \"/proc/cpuinfo\"";
+
+       action = lttng_action_notify_create();
+       if (!action) {
+               fail("Failed to create notify action");
+               goto end;
+       }
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
+       ok(event_rule, "syscall event rule object creation");
+
+       event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
+                       event_rule, syscall_name);
+       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting syscall event rule pattern: '%s'", syscall_name);
+
+       event_rule_status = lttng_event_rule_kernel_syscall_set_filter(
+                       event_rule, filter_pattern);
+       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+                       "Setting filter: '%s'", filter_pattern);
+
+       condition = lttng_condition_event_rule_matches_create(event_rule);
+       ok(condition, "Condition event rule object creation");
+
+       /* Register the triggers for condition */
+       trigger = lttng_trigger_create(condition, action);
+       if (!trigger) {
+               fail("Failed to create trigger with syscall filtering event rule condition and notify action");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to register trigger with syscall filtering event rule condition and notify action");
+               goto end;
+       }
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       resume_application();
+
+       for (i = 0; i < notification_count; i++) {
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+
+               ok(notification, "Received notification (%d/%d)", i + 1,
+                               notification_count);
+
+               /* Error. */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_name(notification, trigger_name);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       suspend_application();
+
+       lttng_unregister_trigger(trigger);
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_trigger_destroy(trigger);
+       lttng_event_rule_destroy(event_rule);
+       lttng_condition_destroy(condition);
+       return;
+}
+
+static int generate_capture_descr(struct lttng_condition *condition)
+{
+       int ret, i;
+       struct lttng_event_expr *expr = NULL;
+       const unsigned int basic_field_count = sizeof(test_capture_base_fields) /
+                       sizeof(*test_capture_base_fields);
+       enum lttng_condition_status cond_status;
+
+       for (i = 0; i < basic_field_count; i++) {
+               diag("Adding capture descriptor '%s'",
+                               test_capture_base_fields[i].field_name);
+
+               switch (test_capture_base_fields[i].field_type) {
+               case FIELD_TYPE_PAYLOAD:
+                       expr = lttng_event_expr_event_payload_field_create(
+                                       test_capture_base_fields[i].field_name);
+                       break;
+               case FIELD_TYPE_CONTEXT:
+                       expr = lttng_event_expr_channel_context_field_create(
+                                       test_capture_base_fields[i].field_name);
+                       break;
+               case FIELD_TYPE_ARRAY_FIELD:
+               {
+                       int nb_matches;
+                       unsigned int index;
+                       char field_name[FIELD_NAME_MAX_LEN];
+                       struct lttng_event_expr *array_expr = NULL;
+
+                       nb_matches = sscanf(test_capture_base_fields[i].field_name,
+                                       "%[^[][%u]", field_name, &index);
+                       if (nb_matches != 2) {
+                               fail("Unexpected array field name format: field name = '%s'",
+                                               test_capture_base_fields[i].field_name);
+                               ret = 1;
+                               goto end;
+                       }
+
+                       array_expr = lttng_event_expr_event_payload_field_create(
+                               field_name);
+
+                       expr = lttng_event_expr_array_field_element_create(
+                               array_expr, index);
+                       break;
+               }
+               case FIELD_TYPE_APP_CONTEXT:
+                       fail("Application context tests are not implemented yet.");
+                       /* fallthrough. */
+               default:
+                       ret = 1;
+                       goto end;
+               }
+
+               if (expr == NULL) {
+                       fail("Failed to create capture expression");
+                       ret = -1;
+                       goto end;
+               }
+
+               cond_status = lttng_condition_event_rule_matches_append_capture_descriptor(
+                               condition, expr);
+               if (cond_status != LTTNG_CONDITION_STATUS_OK) {
+                       fail("Failed to append capture descriptor");
+                       ret = -1;
+                       lttng_event_expr_destroy(expr);
+                       goto end;
+               }
+       }
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static int validator_notification_trigger_capture(
+               enum lttng_domain_type domain,
+               struct lttng_notification *notification,
+               const int iteration)
+{
+       int ret;
+       unsigned int capture_count, i;
+       enum lttng_evaluation_event_rule_matches_status
+                       event_rule_matches_evaluation_status;
+       enum lttng_event_field_value_status event_field_value_status;
+       const struct lttng_evaluation *evaluation;
+       const struct lttng_event_field_value *captured_fields;
+       bool at_least_one_error = false;
+
+       evaluation = lttng_notification_get_evaluation(notification);
+       if (evaluation == NULL) {
+               fail("Failed to get evaluation from notification during trigger capture test");
+               ret = 1;
+               goto end;
+       }
+
+       event_rule_matches_evaluation_status =
+                       lttng_evaluation_event_rule_matches_get_captured_values(
+                                       evaluation, &captured_fields);
+       if (event_rule_matches_evaluation_status !=
+                       LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
+               diag("Failed to get event rule evaluation captured values: status = %d",
+                               (int) event_rule_matches_evaluation_status);
+               ret = 1;
+               goto end;
+       }
+
+       event_field_value_status =
+               lttng_event_field_value_array_get_length(captured_fields,
+                               &capture_count);
+       if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("Failed to get count of captured value field array");
+               ret = 1;
+               goto end;
+       }
+
+       for (i = 0; i < capture_count; i++) {
+               const struct lttng_event_field_value *captured_field = NULL;
+               validate_cb validate;
+               bool expected;
+
+               diag("Validating capture of field '%s'",
+                               test_capture_base_fields[i].field_name);
+               event_field_value_status =
+                               lttng_event_field_value_array_get_element_at_index(
+                                               captured_fields, i,
+                                               &captured_field);
+
+               switch(domain) {
+               case LTTNG_DOMAIN_UST:
+                       expected = test_capture_base_fields[i].expected_ust;
+                       break;
+               case LTTNG_DOMAIN_KERNEL:
+                       expected = test_capture_base_fields[i].expected_kernel;
+                       break;
+               default:
+                       fail("Unexpected domain encountered: domain = %d",
+                                       (int) domain);
+                       ret = 1;
+                       goto end;
+               }
+
+               if (domain == LTTNG_DOMAIN_UST) {
+                       validate = test_capture_base_fields[i].validate_ust;
+               } else {
+                       validate = test_capture_base_fields[i].validate_kernel;
+               }
+
+               if (!expected) {
+                       ok(event_field_value_status == LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE,
+                                       "No payload captured");
+                       continue;
+               }
+
+               if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       if (event_field_value_status ==
+                                       LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
+                               fail("Expected a capture but it is unavailable");
+                       } else {
+                               fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
+                                               (int) event_field_value_status);
+                       }
+
+                       ret = 1;
+                       goto end;
+               }
+
+               diag("Captured field of type %s",
+                               field_value_type_to_str(
+                                       lttng_event_field_value_get_type(captured_field)));
+
+               LTTNG_ASSERT(validate);
+               ret = validate(captured_field, iteration);
+               if (ret) {
+                       at_least_one_error = true;
+               }
+       }
+
+       ret = at_least_one_error;
+
+end:
+       return ret;
+}
+
+static void test_tracepoint_event_rule_notification_capture(
+               enum lttng_domain_type domain_type)
+{
+       enum lttng_notification_channel_status nc_status;
+
+       int i, ret;
+       struct lttng_condition *condition = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_trigger *trigger = NULL;
+       const char *trigger_name = "my_precious";
+       const char *pattern;
+
+       if (domain_type == LTTNG_DOMAIN_UST) {
+               pattern = "tp:tptest";
+       } else {
+               pattern = "lttng_test_filter_event";
+       }
+
+       create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
+                       NULL, domain_type, generate_capture_descr, &condition,
+                       &trigger);
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       resume_application();
+
+       /* Get 3 notifications */
+       for (i = 0; i < 3; i++) {
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+               ok(notification, "Received notification");
+
+               /* Error */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_name(notification, trigger_name);
+               if (ret) {
+                       lttng_notification_destroy(notification);
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_capture(domain_type, notification, i);
+               if (ret) {
+                       lttng_notification_destroy(notification);
+                       goto end;
+               }
+
+               lttng_notification_destroy(notification);
+       }
+
+end:
+       suspend_application();
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_unregister_trigger(trigger);
+       lttng_trigger_destroy(trigger);
+       lttng_condition_destroy(condition);
+       return;
+}
+
+int main(int argc, const char *argv[])
+{
+       int test_scenario;
+       const char *domain_type_string = NULL;
+       enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
+
+       if (argc < 5) {
+               fail("Missing test scenario, domain type, pid, or application state file argument(s)");
+               goto error;
+       }
+
+       test_scenario = atoi(argv[1]);
+       domain_type_string = argv[2];
+       app_pid = (pid_t) atoi(argv[3]);
+       app_state_file = argv[4];
+
+       if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string)) {
+               domain_type = LTTNG_DOMAIN_UST;
+       }
+       if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
+               domain_type = LTTNG_DOMAIN_KERNEL;
+       }
+       if (domain_type == LTTNG_DOMAIN_NONE) {
+               fail("Unknown domain type");
+               goto error;
+       }
+
+       /*
+        * Test cases are responsible for resuming the app when needed
+        * and making sure it's suspended when returning.
+        */
+       suspend_application();
+
+       switch (test_scenario) {
+       case 1:
+       {
+               plan_tests(41);
+
+               /* Test cases that need gen-ust-event testapp. */
+               diag("Test basic notification error paths for %s domain",
+                               domain_type_string);
+               test_invalid_channel_subscription(domain_type);
+
+               diag("Test tracepoint event rule notifications for domain %s",
+                               domain_type_string);
+               test_tracepoint_event_rule_notification(domain_type);
+
+               diag("Test tracepoint event rule notifications with filter for domain %s",
+                               domain_type_string);
+               test_tracepoint_event_rule_notification_filter(domain_type);
+               break;
+       }
+       case 2:
+       {
+               const char *session_name, *channel_name;
+
+               /* Test cases that need a tracing session enabled. */
+               plan_tests(99);
+
+               /*
+                * Argument 7 and upward are named pipe location for consumerd
+                * control.
+                */
+               named_pipe_args_start = 7;
+
+               if (argc < 8) {
+                       fail("Missing parameter for tests to run %d", argc);
+                       goto error;
+               }
+
+               nb_args = argc;
+
+               session_name = argv[5];
+               channel_name = argv[6];
+
+               test_subscription_twice(session_name, channel_name,
+                               domain_type);
+
+               diag("Test trigger for domain %s with buffer_usage_low condition",
+                               domain_type_string);
+               test_triggers_buffer_usage_condition(session_name, channel_name,
+                               domain_type,
+                               LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
+
+               diag("Test trigger for domain %s with buffer_usage_high condition",
+                               domain_type_string);
+               test_triggers_buffer_usage_condition(session_name, channel_name,
+                               domain_type,
+                               LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
+
+               diag("Test buffer usage notification channel api for domain %s",
+                               domain_type_string);
+               test_buffer_usage_notification_channel(session_name, channel_name,
+                               domain_type, argv);
+               break;
+       }
+       case 3:
+       {
+               /*
+                * Test cases that need a test app with more than one event
+                * type.
+                */
+               plan_tests(23);
+
+               /*
+                * At the moment, the only test case of this scenario is
+                * exclusion which is only supported by UST.
+                */
+               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
+               diag("Test tracepoint event rule notifications with exclusion for domain %s",
+                               domain_type_string);
+               test_tracepoint_event_rule_notification_exclusion(domain_type);
+
+               break;
+       }
+       case 4:
+       {
+               plan_tests(11);
+               /* Test cases that need the kernel tracer. */
+               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
+
+               diag("Test kprobe event rule notifications for domain %s",
+                               domain_type_string);
+
+               test_kprobe_event_rule_notification(domain_type);
+
+               break;
+       }
+       case 5:
+       {
+               plan_tests(23);
+               /* Test cases that need the kernel tracer. */
+               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
+
+               diag("Test syscall event rule notifications for domain %s",
+                               domain_type_string);
+
+               test_syscall_event_rule_notification(domain_type);
+
+               diag("Test syscall filtering event rule notifications for domain %s",
+                               domain_type_string);
+
+               test_syscall_event_rule_notification_filter(domain_type);
+
+               break;
+       }
+       case 6:
+       {
+               const char *testapp_path, *test_symbol_name;
+
+               plan_tests(11);
+
+               if (argc < 7) {
+                       fail("Missing parameter for tests to run %d", argc);
+                       goto error;
+               }
+
+               testapp_path = argv[5];
+               test_symbol_name = argv[6];
+               /* Test cases that need the kernel tracer. */
+               LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
+
+               diag("Test userspace-probe event rule notifications for domain %s",
+                               domain_type_string);
+
+               test_uprobe_event_rule_notification(
+                               domain_type, testapp_path, test_symbol_name);
+
+               break;
+       }
+       case 7:
+       {
+               switch(domain_type) {
+               case LTTNG_DOMAIN_UST:
+                       plan_tests(221);
+                       break;
+               case LTTNG_DOMAIN_KERNEL:
+                       plan_tests(215);
+                       break;
+               default:
+                       abort();
+               }
+
+               diag("Test tracepoint event rule notification captures for domain %s",
+                               domain_type_string);
+               test_tracepoint_event_rule_notification_capture(domain_type);
+
+               break;
+       }
+
+       default:
+               abort();
+       }
+
+error:
+       return exit_status();
+}
+
index ef383fde9f7e2283cf65649c95cff6e3d290fd8a..205331c923ca84890475d65d805c0b7451083c34 100644 (file)
@@ -6,8 +6,7 @@ LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
 noinst_PROGRAMS = hidden_trigger
 LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
 noinst_PROGRAMS = hidden_trigger
-hidden_trigger_CFLAGS = $(AM_CFLAGS)
-hidden_trigger_SOURCES = hidden_trigger.c
+hidden_trigger_SOURCES = hidden_trigger.cpp
 hidden_trigger_LDADD = $(LIBTAP) $(LIBLTTNG_CTL)
 
 noinst_SCRIPTS = test_hidden_trigger
 hidden_trigger_LDADD = $(LIBTAP) $(LIBLTTNG_CTL)
 
 noinst_SCRIPTS = test_hidden_trigger
diff --git a/tests/regression/tools/trigger/hidden/hidden_trigger.c b/tests/regression/tools/trigger/hidden/hidden_trigger.c
deleted file mode 100644 (file)
index 8edd97a..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * trigger_name.c
- *
- * Test that hidden triggers are not visible to liblttng-ctl.
- *
- * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <common/macros.h>
-#include <lttng/lttng.h>
-
-#define TEST_COUNT 1
-
-#define TEST_SESSION_NAME "test_session"
-#define TEST_CHANNEL_NAME "test_channel"
-
-static
-int get_registered_triggers_count(void)
-{
-       int ret;
-       enum lttng_error_code ret_code;
-       enum lttng_trigger_status trigger_status;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int trigger_count;
-
-       ret_code = lttng_list_triggers(&triggers);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to list triggers");
-               ret = -1;
-               goto end;
-       }
-
-       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               fail("Failed to get count of triggers returned by listing");
-               ret = -1;
-               goto end;
-       }
-
-       ret = (int) trigger_count;
-
-end:
-       lttng_triggers_destroy(triggers);
-       return ret;
-}
-
-static
-int setup_session_with_size_rotation_schedule(const char *session_output_path)
-{
-       int ret;
-       struct lttng_session_descriptor *session_desriptor = NULL;
-       enum lttng_error_code ret_code;
-       struct lttng_handle ust_channel_handle = {
-               .session_name = TEST_SESSION_NAME,
-               .domain.type = LTTNG_DOMAIN_UST,
-               .domain.buf_type = LTTNG_BUFFER_PER_UID,
-       };
-       struct lttng_channel channel_cfg = {
-               .name = TEST_CHANNEL_NAME,
-               .enabled = 1,
-               .attr.overwrite = -1,
-               .attr.subbuf_size = sysconf(_SC_PAGE_SIZE) * 8,
-               .attr.num_subbuf = 8,
-               .attr.output = LTTNG_EVENT_MMAP,
-       };
-       enum lttng_rotation_status rotation_status;
-       struct lttng_rotation_schedule *rotation_schedule = NULL;
-
-       session_desriptor = lttng_session_descriptor_local_create(
-                       TEST_SESSION_NAME, session_output_path);
-       if (!session_desriptor) {
-               fail("Failed to create session descriptor for session `%s`",
-                               TEST_SESSION_NAME);
-               ret = -1;
-               goto end;
-       }
-
-       ret_code = lttng_create_session_ext(session_desriptor);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to create session `%s`: %s", TEST_SESSION_NAME,
-                               lttng_strerror(-ret_code));
-               ret = -1;
-               goto end;
-       }
-
-       ret = lttng_enable_channel(&ust_channel_handle, &channel_cfg);
-       if (ret) {
-               fail("Failed to enable channel `%s`: %s", TEST_CHANNEL_NAME,
-                               lttng_strerror(ret));
-               ret = -1;
-               goto end;
-       }
-
-       ret = lttng_start_tracing(TEST_SESSION_NAME);
-       if (ret) {
-               fail("Failed to start session `%s`: %s", TEST_SESSION_NAME,
-                               lttng_strerror(ret));
-               ret = -1;
-               goto end;
-       }
-
-       rotation_schedule = lttng_rotation_schedule_size_threshold_create();
-       if (!rotation_schedule) {
-               fail("Failed to create rotation schedule descriptor");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * The rotation schedule size threshold doesn't matter; no event rules
-        * were specified so the session consumed size should not grow over
-        * time.
-        */
-       rotation_status = lttng_rotation_schedule_size_threshold_set_threshold(
-                       rotation_schedule, sysconf(_SC_PAGE_SIZE) * 4096);
-       if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
-               fail("Failed to set size threshold of session rotation schedule");
-               ret = -1;
-               goto end;
-       }
-
-       rotation_status = lttng_session_add_rotation_schedule(
-                       TEST_SESSION_NAME, rotation_schedule);
-       if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
-               fail("Failed to set size-based rotation schedule on session `%s`",
-                               TEST_SESSION_NAME);
-               ret = -1;
-               goto end;
-       }
-
-       ret = 0;
-end:
-       lttng_session_descriptor_destroy(session_desriptor);
-       lttng_rotation_schedule_destroy(rotation_schedule);
-       return ret;
-}
-
-int main(int argc, const char **argv)
-{
-       int ret;
-
-       if (argc != 2) {
-               fail("Missing trace path");
-               goto end;
-       }
-
-       plan_tests(TEST_COUNT);
-
-       if (get_registered_triggers_count() != 0) {
-               fail("Session daemon already has registered triggers, bailing out");
-               goto end;
-       }
-
-       ret = setup_session_with_size_rotation_schedule(argv[1]);
-       if (ret) {
-               goto end;
-       }
-
-       ok(get_registered_triggers_count() == 0,
-                       "No triggers visible while session has an enabled size-based rotation schedule");
-
-       ret = lttng_destroy_session(TEST_SESSION_NAME);
-       if (ret) {
-               fail("Failed to destroy session `%s`", TEST_SESSION_NAME);
-               goto end;
-       }
-end:
-       return exit_status();
-}
diff --git a/tests/regression/tools/trigger/hidden/hidden_trigger.cpp b/tests/regression/tools/trigger/hidden/hidden_trigger.cpp
new file mode 100644 (file)
index 0000000..668a60f
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * trigger_name.c
+ *
+ * Test that hidden triggers are not visible to liblttng-ctl.
+ *
+ * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/macros.h>
+#include <lttng/lttng.h>
+
+#define TEST_COUNT 1
+
+#define TEST_SESSION_NAME "test_session"
+#define TEST_CHANNEL_NAME "test_channel"
+
+static
+int get_registered_triggers_count(void)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       enum lttng_trigger_status trigger_status;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int trigger_count;
+
+       ret_code = lttng_list_triggers(&triggers);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to list triggers");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fail("Failed to get count of triggers returned by listing");
+               ret = -1;
+               goto end;
+       }
+
+       ret = (int) trigger_count;
+
+end:
+       lttng_triggers_destroy(triggers);
+       return ret;
+}
+
+static
+int setup_session_with_size_rotation_schedule(const char *session_output_path)
+{
+       int ret;
+       struct lttng_session_descriptor *session_desriptor = NULL;
+       enum lttng_error_code ret_code;
+       struct lttng_handle ust_channel_handle = {
+               TEST_SESSION_NAME,
+               {
+                       .type = LTTNG_DOMAIN_UST,
+                       .buf_type = LTTNG_BUFFER_PER_UID,
+               }
+       };
+
+       lttng_channel channel_cfg {};
+       strcpy(channel_cfg.name, TEST_CHANNEL_NAME);
+       channel_cfg.enabled = 1;
+       channel_cfg.attr.overwrite = -1;
+       channel_cfg.attr.subbuf_size = (uint64_t) sysconf(_SC_PAGE_SIZE) * 8;
+       channel_cfg.attr.num_subbuf = 8;
+       channel_cfg.attr.output = LTTNG_EVENT_MMAP;
+
+       enum lttng_rotation_status rotation_status;
+       struct lttng_rotation_schedule *rotation_schedule = NULL;
+
+       session_desriptor = lttng_session_descriptor_local_create(
+                       TEST_SESSION_NAME, session_output_path);
+       if (!session_desriptor) {
+               fail("Failed to create session descriptor for session `%s`",
+                               TEST_SESSION_NAME);
+               ret = -1;
+               goto end;
+       }
+
+       ret_code = lttng_create_session_ext(session_desriptor);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to create session `%s`: %s", TEST_SESSION_NAME,
+                               lttng_strerror(-ret_code));
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_enable_channel(&ust_channel_handle, &channel_cfg);
+       if (ret) {
+               fail("Failed to enable channel `%s`: %s", TEST_CHANNEL_NAME,
+                               lttng_strerror(ret));
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_start_tracing(TEST_SESSION_NAME);
+       if (ret) {
+               fail("Failed to start session `%s`: %s", TEST_SESSION_NAME,
+                               lttng_strerror(ret));
+               ret = -1;
+               goto end;
+       }
+
+       rotation_schedule = lttng_rotation_schedule_size_threshold_create();
+       if (!rotation_schedule) {
+               fail("Failed to create rotation schedule descriptor");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * The rotation schedule size threshold doesn't matter; no event rules
+        * were specified so the session consumed size should not grow over
+        * time.
+        */
+       rotation_status = lttng_rotation_schedule_size_threshold_set_threshold(
+                       rotation_schedule, sysconf(_SC_PAGE_SIZE) * 4096);
+       if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+               fail("Failed to set size threshold of session rotation schedule");
+               ret = -1;
+               goto end;
+       }
+
+       rotation_status = lttng_session_add_rotation_schedule(
+                       TEST_SESSION_NAME, rotation_schedule);
+       if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+               fail("Failed to set size-based rotation schedule on session `%s`",
+                               TEST_SESSION_NAME);
+               ret = -1;
+               goto end;
+       }
+
+       ret = 0;
+end:
+       lttng_session_descriptor_destroy(session_desriptor);
+       lttng_rotation_schedule_destroy(rotation_schedule);
+       return ret;
+}
+
+int main(int argc, const char **argv)
+{
+       int ret;
+
+       if (argc != 2) {
+               fail("Missing trace path");
+               goto end;
+       }
+
+       plan_tests(TEST_COUNT);
+
+       if (get_registered_triggers_count() != 0) {
+               fail("Session daemon already has registered triggers, bailing out");
+               goto end;
+       }
+
+       ret = setup_session_with_size_rotation_schedule(argv[1]);
+       if (ret) {
+               goto end;
+       }
+
+       ok(get_registered_triggers_count() == 0,
+                       "No triggers visible while session has an enabled size-based rotation schedule");
+
+       ret = lttng_destroy_session(TEST_SESSION_NAME);
+       if (ret) {
+               fail("Failed to destroy session `%s`", TEST_SESSION_NAME);
+               goto end;
+       }
+end:
+       return exit_status();
+}
index d4bc5ed06e7d383069bbfb03d29e4275cf8e1591..bd267b8866db33c97ddc426ebe2e6c6dbb1ba7ef 100644 (file)
@@ -7,8 +7,8 @@ LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
 noinst_PROGRAMS = trigger_name
 # This test explicitly tests APIs that were marked as deprecated.
 
 noinst_PROGRAMS = trigger_name
 # This test explicitly tests APIs that were marked as deprecated.
-trigger_name_CFLAGS = -Wno-deprecated-declarations $(AM_CFLAGS)
-trigger_name_SOURCES = trigger_name.c
+trigger_name_CXXFLAGS = -Wno-deprecated-declarations $(AM_CXXFLAGS)
+trigger_name_SOURCES = trigger_name.cpp
 trigger_name_LDADD = $(LIBTAP) $(LIBLTTNG_CTL)
 
 noinst_SCRIPTS = test_trigger_name_backwards_compat
 trigger_name_LDADD = $(LIBTAP) $(LIBLTTNG_CTL)
 
 noinst_SCRIPTS = test_trigger_name_backwards_compat
diff --git a/tests/regression/tools/trigger/name/trigger_name.c b/tests/regression/tools/trigger/name/trigger_name.c
deleted file mode 100644 (file)
index 3bb3099..0000000
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * trigger_name.c
- *
- * Tests suite for anonymous, named, and automatic name triggers.
- *
- * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <tap/tap.h>
-#include <stdint.h>
-#include <string.h>
-#include <lttng/lttng.h>
-#include <common/macros.h>
-
-#define TEST_COUNT 70
-
-enum unregistration_trigger_instance {
-       UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION,
-       UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING,
-};
-
-typedef void (*test_function)(enum unregistration_trigger_instance);
-
-static
-const char *get_trigger_name(const struct lttng_trigger *trigger)
-{
-       const char *trigger_name;
-       enum lttng_trigger_status trigger_status;
-
-       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-       switch (trigger_status) {
-       case LTTNG_TRIGGER_STATUS_OK:
-               break;
-       case LTTNG_TRIGGER_STATUS_UNSET:
-               trigger_name = "(anonymous)";
-               break;
-       default:
-               trigger_name = "(failed to get name)";
-               break;
-       }
-
-       return trigger_name;
-}
-
-static
-const char *unregistration_trigger_instance_name(
-               enum unregistration_trigger_instance unregistration_trigger)
-{
-       const char *name;
-
-       switch (unregistration_trigger) {
-       case UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING:
-               name = "from listing";
-               break;
-       case UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION:
-               name = "used for registration";
-               break;
-       default:
-               abort();
-       }
-
-       return name;
-}
-
-/*
- * Returns a negative error code on error, else the number of unregistered
- * triggers.
- */
-static
-int unregister_all_triggers(void)
-{
-       int ret;
-       enum lttng_error_code ret_code;
-       enum lttng_trigger_status trigger_status;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int trigger_count, i, unregistered_trigger_count = 0;
-
-       ret_code = lttng_list_triggers(&triggers);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to list triggers");
-               ret = -1;
-               goto end;
-       }
-
-       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               fail("Failed to get count of triggers returned by listing");
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < trigger_count; i++) {
-               const struct lttng_trigger *trigger;
-
-               trigger = lttng_triggers_get_at_index(triggers, i);
-               LTTNG_ASSERT(trigger);
-
-               ret = lttng_unregister_trigger(trigger);
-               if (ret) {
-                       fail("Failed to unregister trigger: trigger name = '%s'");
-                       goto end;
-               }
-
-               unregistered_trigger_count++;
-       }
-
-       ret = (int) unregistered_trigger_count;
-
-end:
-       lttng_triggers_destroy(triggers);
-       return ret;
-}
-
-static
-int get_registered_triggers_count(void)
-{
-       int ret;
-       enum lttng_error_code ret_code;
-       enum lttng_trigger_status trigger_status;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int trigger_count;
-
-       ret_code = lttng_list_triggers(&triggers);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to list triggers");
-               ret = -1;
-               goto end;
-       }
-
-       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               fail("Failed to get count of triggers returned by listing");
-               ret = -1;
-               goto end;
-       }
-
-       ret = (int) trigger_count;
-
-end:
-       lttng_triggers_destroy(triggers);
-       return ret;
-}
-
-/*
- * Create a generic trigger. The specifics of the condition and action are not
- * important for the purposes of this test.
- */
-static
-struct lttng_trigger *create_trigger(uint64_t threshold)
-{
-       struct lttng_condition *condition = NULL;
-       struct lttng_action *action = NULL;
-       struct lttng_trigger *trigger = NULL;
-       enum lttng_condition_status condition_status;
-       const char * const session_name = "test session";
-
-       condition = lttng_condition_session_consumed_size_create();
-       if (!condition) {
-               fail("Failed to create 'session consumed size' condition");
-               goto end;
-       }
-
-       condition_status = lttng_condition_session_consumed_size_set_session_name(condition, session_name);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               fail("Failed to set session name on 'session consumed size' condition");
-               goto end;
-       }
-
-       condition_status = lttng_condition_session_consumed_size_set_threshold(
-                       condition, threshold);
-       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
-               fail("Failed to set threshold on 'session consumed size' condition");
-               goto end;
-       }
-
-       action = lttng_action_notify_create();
-       if (!action) {
-               fail("Failed to create 'notify' action");
-               goto end;
-       }
-
-       trigger = lttng_trigger_create(condition, action);
-       if (!trigger) {
-               fail("Failed to create trigger");
-               goto end;
-       }
-
-end:
-       lttng_condition_destroy(condition);
-       lttng_action_destroy(action);
-       return trigger;
-}
-
-static
-void register_anonymous_trigger(
-               enum unregistration_trigger_instance unregistration_trigger)
-{
-       int ret;
-       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
-       enum lttng_trigger_status trigger_status;
-       const char *trigger_name;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int trigger_count, i;
-       enum lttng_error_code ret_code;
-
-       diag("Register an anonymous trigger (Unregistration performed with the trigger instance %s)",
-                       unregistration_trigger_instance_name(
-                                       unregistration_trigger));
-
-       if (!trigger) {
-               fail("Failed to create trigger");
-               goto end;
-       }
-
-       ret = lttng_register_trigger(trigger);
-       ok(ret == 0, "Registered anonymous trigger");
-
-       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-       ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
-                       "Anonymous trigger name remains unset after registration: trigger name = '%s'",
-                       get_trigger_name(trigger));
-
-       ret_code = lttng_list_triggers(&triggers);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to list triggers");
-               ret = -1;
-               goto end;
-       }
-
-       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               fail("Failed to get count of triggers returned by listing");
-               ret = -1;
-               goto end;
-       }
-
-       ok(trigger_count == 1, "Trigger listing returns 1 trigger");
-
-       for (i = 0; i < trigger_count; i++) {
-               const struct lttng_trigger *trigger_from_listing;
-
-               trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
-               LTTNG_ASSERT(trigger_from_listing);
-
-               trigger_status = lttng_trigger_get_name(trigger_from_listing, &trigger_name);
-               ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
-                               "Anonymous trigger returned by listing has an unset name: trigger name = '%s'",
-                               get_trigger_name(trigger_from_listing));
-
-               if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
-                       ret = lttng_unregister_trigger(trigger_from_listing);
-                       ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
-               }
-       }
-
-       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
-               ret = lttng_unregister_trigger(trigger);
-               ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
-       }
-
-end:
-       lttng_triggers_destroy(triggers);
-       lttng_trigger_destroy(trigger);
-}
-
-static
-void register_named_trigger(
-               enum unregistration_trigger_instance unregistration_trigger)
-{
-       int ret;
-       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
-       enum lttng_trigger_status trigger_status;
-       const char *returned_trigger_name;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int trigger_count, i;
-       enum lttng_error_code ret_code;
-       const char * const trigger_name = "some name that is hopefully unique";
-
-       diag("Register a named trigger (Unregistration performed with the trigger instance %s)",
-                       unregistration_trigger_instance_name(
-                                       unregistration_trigger));
-
-       if (!trigger) {
-               fail("Failed to create trigger");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
-       ok(ret_code == LTTNG_OK, "Registered trigger with name: trigger name = '%s'",
-                       get_trigger_name(trigger));
-
-       trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
-       ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
-                       "Trigger name is set after registration: trigger name = '%s'",
-                       get_trigger_name(trigger));
-
-       ok(!strcmp(get_trigger_name(trigger), trigger_name),
-                       "Name set on trigger after registration is correct");
-
-       ret_code = lttng_list_triggers(&triggers);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to list triggers");
-               ret = -1;
-               goto end;
-       }
-
-       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               fail("Failed to get count of triggers returned by listing");
-               ret = -1;
-               goto end;
-       }
-
-       ok(trigger_count == 1, "Trigger listing returns 1 trigger");
-
-       for (i = 0; i < trigger_count; i++) {
-               const struct lttng_trigger *trigger_from_listing;
-
-               trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
-               LTTNG_ASSERT(trigger_from_listing);
-
-               trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
-               ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
-                               "Trigger returned by listing has a name: trigger name = '%s'",
-                               get_trigger_name(trigger_from_listing));
-
-               ok(!strcmp(get_trigger_name(trigger_from_listing),
-                               trigger_name),
-                               "Name set on trigger returned from listing is correct: name returned from listing = '%s', expected name = '%s'",
-                               get_trigger_name(trigger_from_listing),
-                               trigger_name);
-
-               if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
-                       ret = lttng_unregister_trigger(trigger_from_listing);
-                       ok(ret == 0, "Successfully unregistered named trigger using the trigger instance returned by the listing");
-               }
-       }
-
-       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
-               ret = lttng_unregister_trigger(trigger);
-               ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
-       }
-
-end:
-       lttng_triggers_destroy(triggers);
-       lttng_trigger_destroy(trigger);
-}
-
-static
-void register_automatic_name_trigger(
-               enum unregistration_trigger_instance unregistration_trigger)
-{
-       int ret;
-       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
-       enum lttng_trigger_status trigger_status;
-       const char *returned_trigger_name;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int trigger_count, i;
-       enum lttng_error_code ret_code;
-
-       diag("Register an automatic name trigger (Unregistration performed with the trigger instance %s)",
-                       unregistration_trigger_instance_name(
-                                       unregistration_trigger));
-
-       if (!trigger) {
-               fail("Failed to create trigger");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_automatic_name(trigger);
-       ok(ret_code == LTTNG_OK, "Registered trigger with automatic name");
-
-       trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
-       ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
-                       "Trigger name is set after registration: trigger name = '%s'",
-                       get_trigger_name(trigger));
-
-       ok(returned_trigger_name && strlen(returned_trigger_name) > 0,
-                       "Automatic name set on trigger after registration longer is not an empty string");
-
-       ret_code = lttng_list_triggers(&triggers);
-       if (ret_code != LTTNG_OK) {
-               fail("Failed to list triggers");
-               ret = -1;
-               goto end;
-       }
-
-       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               fail("Failed to get count of triggers returned by listing");
-               ret = -1;
-               goto end;
-       }
-
-       ok(trigger_count == 1, "Trigger listing returns 1 trigger");
-
-       for (i = 0; i < trigger_count; i++) {
-               const struct lttng_trigger *trigger_from_listing;
-
-               trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
-               LTTNG_ASSERT(trigger_from_listing);
-
-               trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
-               ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
-                               "Trigger returned by listing has a name: trigger name = '%s'",
-                               get_trigger_name(trigger_from_listing));
-
-               if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
-                       ret = lttng_unregister_trigger(trigger_from_listing);
-                       ok(ret == 0, "Successfully unregistered automatic name trigger using the trigger instance returned by the listing");
-               }
-       }
-
-       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
-               ret = lttng_unregister_trigger(trigger);
-               ok(ret == 0, "Successfully unregistered automatic trigger using the trigger instance used on registration");
-       }
-
-end:
-       lttng_triggers_destroy(triggers);
-       lttng_trigger_destroy(trigger);
-}
-
-static
-void double_register_anonymous_trigger(
-               enum unregistration_trigger_instance unregistration_trigger)
-{
-       int ret;
-       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
-       struct lttng_triggers *triggers = NULL;
-
-       diag("Register duplicate anonymous trigger (Unregistration performed with the trigger instance %s)",
-                       unregistration_trigger_instance_name(
-                                       unregistration_trigger));
-
-       if (!trigger) {
-               fail("Failed to create trigger");
-               goto end;
-       }
-
-       ret = lttng_register_trigger(trigger);
-       ok(ret == 0, "Registered anonymous trigger");
-
-       ret = lttng_register_trigger(trigger);
-       ok(ret == -LTTNG_ERR_TRIGGER_EXISTS,
-                       "Registering identical anonymous trigger fails with `LTTNG_ERR_TRIGGER_EXISTS`");
-
-
-       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
-               ret = lttng_unregister_trigger(trigger);
-               ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
-       } else {
-               ok(get_registered_triggers_count() == 1,
-                               "Trigger listing returns 1 trigger");
-               ok(unregister_all_triggers() == 1,
-                               "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
-       }
-
-end:
-       lttng_triggers_destroy(triggers);
-       lttng_trigger_destroy(trigger);
-}
-
-static
-void double_register_named_trigger(
-               enum unregistration_trigger_instance unregistration_trigger)
-{
-       int ret;
-       struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
-       struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
-       struct lttng_triggers *triggers = NULL;
-       const char * const trigger_name = "a unique trigger name";
-       enum lttng_error_code ret_code;
-
-       diag("Register duplicate named trigger (Unregistration performed with the trigger instance %s)",
-                       unregistration_trigger_instance_name(
-                                       unregistration_trigger));
-
-       if (!trigger_a || !trigger_b) {
-               fail("Failed to create triggers");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
-       ok(ret_code == LTTNG_OK, "Registered named trigger");
-
-       ret = lttng_register_trigger(trigger_a);
-       ok(ret == -LTTNG_ERR_INVALID,
-                       "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (anonymous registration)");
-
-       ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
-       ok(ret_code == LTTNG_ERR_INVALID,
-                       "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with name)");
-
-       ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
-       ok(ret_code == LTTNG_ERR_INVALID,
-                       "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with automatic name)");
-
-       ret_code = lttng_register_trigger_with_name(trigger_b, trigger_name);
-       ok(ret_code == LTTNG_ERR_TRIGGER_EXISTS, "Registering trigger with an already used name fails with `LTTNG_ERR_TRIGGER_EXISTS`");
-
-       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
-               ret = lttng_unregister_trigger(trigger_a);
-               ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
-       } else {
-               ok(get_registered_triggers_count() == 1,
-                               "Trigger listing returns 1 trigger");
-               ok(unregister_all_triggers() == 1,
-                               "Successfully unregistered named trigger using the trigger instance returned by the listing");
-       }
-
-end:
-       lttng_triggers_destroy(triggers);
-       lttng_trigger_destroy(trigger_a);
-       lttng_trigger_destroy(trigger_b);
-}
-
-static
-void double_register_automatic_name_trigger(
-               enum unregistration_trigger_instance unregistration_trigger)
-{
-       int ret;
-       struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
-       struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
-       struct lttng_triggers *triggers = NULL;
-       enum lttng_error_code ret_code;
-
-       diag("Register duplicate automatic name trigger (Unregistration performed with the trigger instance %s)",
-                       unregistration_trigger_instance_name(
-                                       unregistration_trigger));
-
-       if (!trigger_a || !trigger_b) {
-               fail("Failed to create triggers");
-               goto end;
-       }
-
-       ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
-       ok(ret_code == LTTNG_OK, "Registered automatic name trigger: trigger name = '%s'", get_trigger_name(trigger_a));
-
-       ret = lttng_register_trigger_with_automatic_name(trigger_b);
-       ok(ret_code == LTTNG_OK, "Registering an identical trigger instance with an automatic name succeeds: trigger name = '%s'", get_trigger_name(trigger_b));
-
-       ok(strcmp(get_trigger_name(trigger_a), get_trigger_name(trigger_b)),
-                       "Two identical triggers registered with an automatic name have different names");
-
-       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
-               ret = lttng_unregister_trigger(trigger_a);
-               ok(ret == 0, "Successfully unregistered automatic trigger A using the trigger instance used on registration");
-
-               ret = lttng_unregister_trigger(trigger_b);
-               ok(ret == 0, "Successfully unregistered automatic trigger B using the trigger instance used on registration");
-       } else {
-               ok(get_registered_triggers_count() == 2,
-                               "Trigger listing returns 2 trigger");
-               ok(unregister_all_triggers() == 2,
-                               "Successfully unregistered automatic name triggers using the trigger instance returned by the listing");
-       }
-
-end:
-       lttng_triggers_destroy(triggers);
-       lttng_trigger_destroy(trigger_a);
-       lttng_trigger_destroy(trigger_b);
-}
-
-static
-void register_multiple_anonymous_triggers(void)
-{
-       int ret;
-       struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
-       struct lttng_trigger *trigger_b = create_trigger(0xbadf00d);
-
-       diag("Register two different anonymous triggers");
-
-       if (!trigger_a || !trigger_b) {
-               fail("Failed to create triggers");
-               goto end;
-       }
-
-       ret = lttng_register_trigger(trigger_a);
-       ok(ret == 0, "Registered first anonymous trigger");
-
-       ret = lttng_register_trigger(trigger_b);
-       ok(ret == 0, "Registered second anonymous trigger");
-
-       ok(get_registered_triggers_count() == 2,
-                       "Trigger listing returns 2 trigger");
-       ok(unregister_all_triggers() == 2,
-                       "Successfully unregistered two anonymous triggers");
-
-end:
-       lttng_trigger_destroy(trigger_a);
-       lttng_trigger_destroy(trigger_b);
-}
-
-const test_function test_functions[] = {
-       register_anonymous_trigger,
-       register_named_trigger,
-       register_automatic_name_trigger,
-       double_register_anonymous_trigger,
-       double_register_named_trigger,
-       double_register_automatic_name_trigger,
-};
-
-int main(int argc, const char **argv)
-{
-       size_t i;
-
-       plan_tests(TEST_COUNT);
-
-       if (get_registered_triggers_count() != 0) {
-               fail("Session daemon already has registered triggers, bailing out");
-               goto end;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
-               const test_function fn = test_functions[i];
-
-               fn(UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING);
-               if (get_registered_triggers_count() != 0) {
-                       fail("Previous test left registered triggers, bailing out");
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
-               const test_function fn = test_functions[i];
-
-               fn(UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION);
-               if (get_registered_triggers_count() != 0) {
-                       fail("Previous test left registered triggers, bailing out");
-                       goto end;
-               }
-       }
-
-       register_multiple_anonymous_triggers();
-end:
-       return exit_status();
-}
diff --git a/tests/regression/tools/trigger/name/trigger_name.cpp b/tests/regression/tools/trigger/name/trigger_name.cpp
new file mode 100644 (file)
index 0000000..3bb3099
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * trigger_name.c
+ *
+ * Tests suite for anonymous, named, and automatic name triggers.
+ *
+ * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <tap/tap.h>
+#include <stdint.h>
+#include <string.h>
+#include <lttng/lttng.h>
+#include <common/macros.h>
+
+#define TEST_COUNT 70
+
+enum unregistration_trigger_instance {
+       UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION,
+       UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING,
+};
+
+typedef void (*test_function)(enum unregistration_trigger_instance);
+
+static
+const char *get_trigger_name(const struct lttng_trigger *trigger)
+{
+       const char *trigger_name;
+       enum lttng_trigger_status trigger_status;
+
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       switch (trigger_status) {
+       case LTTNG_TRIGGER_STATUS_OK:
+               break;
+       case LTTNG_TRIGGER_STATUS_UNSET:
+               trigger_name = "(anonymous)";
+               break;
+       default:
+               trigger_name = "(failed to get name)";
+               break;
+       }
+
+       return trigger_name;
+}
+
+static
+const char *unregistration_trigger_instance_name(
+               enum unregistration_trigger_instance unregistration_trigger)
+{
+       const char *name;
+
+       switch (unregistration_trigger) {
+       case UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING:
+               name = "from listing";
+               break;
+       case UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION:
+               name = "used for registration";
+               break;
+       default:
+               abort();
+       }
+
+       return name;
+}
+
+/*
+ * Returns a negative error code on error, else the number of unregistered
+ * triggers.
+ */
+static
+int unregister_all_triggers(void)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       enum lttng_trigger_status trigger_status;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int trigger_count, i, unregistered_trigger_count = 0;
+
+       ret_code = lttng_list_triggers(&triggers);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to list triggers");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fail("Failed to get count of triggers returned by listing");
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < trigger_count; i++) {
+               const struct lttng_trigger *trigger;
+
+               trigger = lttng_triggers_get_at_index(triggers, i);
+               LTTNG_ASSERT(trigger);
+
+               ret = lttng_unregister_trigger(trigger);
+               if (ret) {
+                       fail("Failed to unregister trigger: trigger name = '%s'");
+                       goto end;
+               }
+
+               unregistered_trigger_count++;
+       }
+
+       ret = (int) unregistered_trigger_count;
+
+end:
+       lttng_triggers_destroy(triggers);
+       return ret;
+}
+
+static
+int get_registered_triggers_count(void)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       enum lttng_trigger_status trigger_status;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int trigger_count;
+
+       ret_code = lttng_list_triggers(&triggers);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to list triggers");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fail("Failed to get count of triggers returned by listing");
+               ret = -1;
+               goto end;
+       }
+
+       ret = (int) trigger_count;
+
+end:
+       lttng_triggers_destroy(triggers);
+       return ret;
+}
+
+/*
+ * Create a generic trigger. The specifics of the condition and action are not
+ * important for the purposes of this test.
+ */
+static
+struct lttng_trigger *create_trigger(uint64_t threshold)
+{
+       struct lttng_condition *condition = NULL;
+       struct lttng_action *action = NULL;
+       struct lttng_trigger *trigger = NULL;
+       enum lttng_condition_status condition_status;
+       const char * const session_name = "test session";
+
+       condition = lttng_condition_session_consumed_size_create();
+       if (!condition) {
+               fail("Failed to create 'session consumed size' condition");
+               goto end;
+       }
+
+       condition_status = lttng_condition_session_consumed_size_set_session_name(condition, session_name);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               fail("Failed to set session name on 'session consumed size' condition");
+               goto end;
+       }
+
+       condition_status = lttng_condition_session_consumed_size_set_threshold(
+                       condition, threshold);
+       if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+               fail("Failed to set threshold on 'session consumed size' condition");
+               goto end;
+       }
+
+       action = lttng_action_notify_create();
+       if (!action) {
+               fail("Failed to create 'notify' action");
+               goto end;
+       }
+
+       trigger = lttng_trigger_create(condition, action);
+       if (!trigger) {
+               fail("Failed to create trigger");
+               goto end;
+       }
+
+end:
+       lttng_condition_destroy(condition);
+       lttng_action_destroy(action);
+       return trigger;
+}
+
+static
+void register_anonymous_trigger(
+               enum unregistration_trigger_instance unregistration_trigger)
+{
+       int ret;
+       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+       enum lttng_trigger_status trigger_status;
+       const char *trigger_name;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int trigger_count, i;
+       enum lttng_error_code ret_code;
+
+       diag("Register an anonymous trigger (Unregistration performed with the trigger instance %s)",
+                       unregistration_trigger_instance_name(
+                                       unregistration_trigger));
+
+       if (!trigger) {
+               fail("Failed to create trigger");
+               goto end;
+       }
+
+       ret = lttng_register_trigger(trigger);
+       ok(ret == 0, "Registered anonymous trigger");
+
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
+                       "Anonymous trigger name remains unset after registration: trigger name = '%s'",
+                       get_trigger_name(trigger));
+
+       ret_code = lttng_list_triggers(&triggers);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to list triggers");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fail("Failed to get count of triggers returned by listing");
+               ret = -1;
+               goto end;
+       }
+
+       ok(trigger_count == 1, "Trigger listing returns 1 trigger");
+
+       for (i = 0; i < trigger_count; i++) {
+               const struct lttng_trigger *trigger_from_listing;
+
+               trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
+               LTTNG_ASSERT(trigger_from_listing);
+
+               trigger_status = lttng_trigger_get_name(trigger_from_listing, &trigger_name);
+               ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
+                               "Anonymous trigger returned by listing has an unset name: trigger name = '%s'",
+                               get_trigger_name(trigger_from_listing));
+
+               if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
+                       ret = lttng_unregister_trigger(trigger_from_listing);
+                       ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
+               }
+       }
+
+       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+               ret = lttng_unregister_trigger(trigger);
+               ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
+       }
+
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_trigger_destroy(trigger);
+}
+
+static
+void register_named_trigger(
+               enum unregistration_trigger_instance unregistration_trigger)
+{
+       int ret;
+       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+       enum lttng_trigger_status trigger_status;
+       const char *returned_trigger_name;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int trigger_count, i;
+       enum lttng_error_code ret_code;
+       const char * const trigger_name = "some name that is hopefully unique";
+
+       diag("Register a named trigger (Unregistration performed with the trigger instance %s)",
+                       unregistration_trigger_instance_name(
+                                       unregistration_trigger));
+
+       if (!trigger) {
+               fail("Failed to create trigger");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+       ok(ret_code == LTTNG_OK, "Registered trigger with name: trigger name = '%s'",
+                       get_trigger_name(trigger));
+
+       trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
+       ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+                       "Trigger name is set after registration: trigger name = '%s'",
+                       get_trigger_name(trigger));
+
+       ok(!strcmp(get_trigger_name(trigger), trigger_name),
+                       "Name set on trigger after registration is correct");
+
+       ret_code = lttng_list_triggers(&triggers);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to list triggers");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fail("Failed to get count of triggers returned by listing");
+               ret = -1;
+               goto end;
+       }
+
+       ok(trigger_count == 1, "Trigger listing returns 1 trigger");
+
+       for (i = 0; i < trigger_count; i++) {
+               const struct lttng_trigger *trigger_from_listing;
+
+               trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
+               LTTNG_ASSERT(trigger_from_listing);
+
+               trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
+               ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+                               "Trigger returned by listing has a name: trigger name = '%s'",
+                               get_trigger_name(trigger_from_listing));
+
+               ok(!strcmp(get_trigger_name(trigger_from_listing),
+                               trigger_name),
+                               "Name set on trigger returned from listing is correct: name returned from listing = '%s', expected name = '%s'",
+                               get_trigger_name(trigger_from_listing),
+                               trigger_name);
+
+               if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
+                       ret = lttng_unregister_trigger(trigger_from_listing);
+                       ok(ret == 0, "Successfully unregistered named trigger using the trigger instance returned by the listing");
+               }
+       }
+
+       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+               ret = lttng_unregister_trigger(trigger);
+               ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
+       }
+
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_trigger_destroy(trigger);
+}
+
+static
+void register_automatic_name_trigger(
+               enum unregistration_trigger_instance unregistration_trigger)
+{
+       int ret;
+       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+       enum lttng_trigger_status trigger_status;
+       const char *returned_trigger_name;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int trigger_count, i;
+       enum lttng_error_code ret_code;
+
+       diag("Register an automatic name trigger (Unregistration performed with the trigger instance %s)",
+                       unregistration_trigger_instance_name(
+                                       unregistration_trigger));
+
+       if (!trigger) {
+               fail("Failed to create trigger");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_automatic_name(trigger);
+       ok(ret_code == LTTNG_OK, "Registered trigger with automatic name");
+
+       trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
+       ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+                       "Trigger name is set after registration: trigger name = '%s'",
+                       get_trigger_name(trigger));
+
+       ok(returned_trigger_name && strlen(returned_trigger_name) > 0,
+                       "Automatic name set on trigger after registration longer is not an empty string");
+
+       ret_code = lttng_list_triggers(&triggers);
+       if (ret_code != LTTNG_OK) {
+               fail("Failed to list triggers");
+               ret = -1;
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fail("Failed to get count of triggers returned by listing");
+               ret = -1;
+               goto end;
+       }
+
+       ok(trigger_count == 1, "Trigger listing returns 1 trigger");
+
+       for (i = 0; i < trigger_count; i++) {
+               const struct lttng_trigger *trigger_from_listing;
+
+               trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
+               LTTNG_ASSERT(trigger_from_listing);
+
+               trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
+               ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+                               "Trigger returned by listing has a name: trigger name = '%s'",
+                               get_trigger_name(trigger_from_listing));
+
+               if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
+                       ret = lttng_unregister_trigger(trigger_from_listing);
+                       ok(ret == 0, "Successfully unregistered automatic name trigger using the trigger instance returned by the listing");
+               }
+       }
+
+       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+               ret = lttng_unregister_trigger(trigger);
+               ok(ret == 0, "Successfully unregistered automatic trigger using the trigger instance used on registration");
+       }
+
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_trigger_destroy(trigger);
+}
+
+static
+void double_register_anonymous_trigger(
+               enum unregistration_trigger_instance unregistration_trigger)
+{
+       int ret;
+       struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+       struct lttng_triggers *triggers = NULL;
+
+       diag("Register duplicate anonymous trigger (Unregistration performed with the trigger instance %s)",
+                       unregistration_trigger_instance_name(
+                                       unregistration_trigger));
+
+       if (!trigger) {
+               fail("Failed to create trigger");
+               goto end;
+       }
+
+       ret = lttng_register_trigger(trigger);
+       ok(ret == 0, "Registered anonymous trigger");
+
+       ret = lttng_register_trigger(trigger);
+       ok(ret == -LTTNG_ERR_TRIGGER_EXISTS,
+                       "Registering identical anonymous trigger fails with `LTTNG_ERR_TRIGGER_EXISTS`");
+
+
+       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+               ret = lttng_unregister_trigger(trigger);
+               ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
+       } else {
+               ok(get_registered_triggers_count() == 1,
+                               "Trigger listing returns 1 trigger");
+               ok(unregister_all_triggers() == 1,
+                               "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
+       }
+
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_trigger_destroy(trigger);
+}
+
+static
+void double_register_named_trigger(
+               enum unregistration_trigger_instance unregistration_trigger)
+{
+       int ret;
+       struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
+       struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
+       struct lttng_triggers *triggers = NULL;
+       const char * const trigger_name = "a unique trigger name";
+       enum lttng_error_code ret_code;
+
+       diag("Register duplicate named trigger (Unregistration performed with the trigger instance %s)",
+                       unregistration_trigger_instance_name(
+                                       unregistration_trigger));
+
+       if (!trigger_a || !trigger_b) {
+               fail("Failed to create triggers");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
+       ok(ret_code == LTTNG_OK, "Registered named trigger");
+
+       ret = lttng_register_trigger(trigger_a);
+       ok(ret == -LTTNG_ERR_INVALID,
+                       "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (anonymous registration)");
+
+       ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
+       ok(ret_code == LTTNG_ERR_INVALID,
+                       "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with name)");
+
+       ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
+       ok(ret_code == LTTNG_ERR_INVALID,
+                       "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with automatic name)");
+
+       ret_code = lttng_register_trigger_with_name(trigger_b, trigger_name);
+       ok(ret_code == LTTNG_ERR_TRIGGER_EXISTS, "Registering trigger with an already used name fails with `LTTNG_ERR_TRIGGER_EXISTS`");
+
+       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+               ret = lttng_unregister_trigger(trigger_a);
+               ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
+       } else {
+               ok(get_registered_triggers_count() == 1,
+                               "Trigger listing returns 1 trigger");
+               ok(unregister_all_triggers() == 1,
+                               "Successfully unregistered named trigger using the trigger instance returned by the listing");
+       }
+
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_trigger_destroy(trigger_a);
+       lttng_trigger_destroy(trigger_b);
+}
+
+static
+void double_register_automatic_name_trigger(
+               enum unregistration_trigger_instance unregistration_trigger)
+{
+       int ret;
+       struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
+       struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
+       struct lttng_triggers *triggers = NULL;
+       enum lttng_error_code ret_code;
+
+       diag("Register duplicate automatic name trigger (Unregistration performed with the trigger instance %s)",
+                       unregistration_trigger_instance_name(
+                                       unregistration_trigger));
+
+       if (!trigger_a || !trigger_b) {
+               fail("Failed to create triggers");
+               goto end;
+       }
+
+       ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
+       ok(ret_code == LTTNG_OK, "Registered automatic name trigger: trigger name = '%s'", get_trigger_name(trigger_a));
+
+       ret = lttng_register_trigger_with_automatic_name(trigger_b);
+       ok(ret_code == LTTNG_OK, "Registering an identical trigger instance with an automatic name succeeds: trigger name = '%s'", get_trigger_name(trigger_b));
+
+       ok(strcmp(get_trigger_name(trigger_a), get_trigger_name(trigger_b)),
+                       "Two identical triggers registered with an automatic name have different names");
+
+       if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+               ret = lttng_unregister_trigger(trigger_a);
+               ok(ret == 0, "Successfully unregistered automatic trigger A using the trigger instance used on registration");
+
+               ret = lttng_unregister_trigger(trigger_b);
+               ok(ret == 0, "Successfully unregistered automatic trigger B using the trigger instance used on registration");
+       } else {
+               ok(get_registered_triggers_count() == 2,
+                               "Trigger listing returns 2 trigger");
+               ok(unregister_all_triggers() == 2,
+                               "Successfully unregistered automatic name triggers using the trigger instance returned by the listing");
+       }
+
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_trigger_destroy(trigger_a);
+       lttng_trigger_destroy(trigger_b);
+}
+
+static
+void register_multiple_anonymous_triggers(void)
+{
+       int ret;
+       struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
+       struct lttng_trigger *trigger_b = create_trigger(0xbadf00d);
+
+       diag("Register two different anonymous triggers");
+
+       if (!trigger_a || !trigger_b) {
+               fail("Failed to create triggers");
+               goto end;
+       }
+
+       ret = lttng_register_trigger(trigger_a);
+       ok(ret == 0, "Registered first anonymous trigger");
+
+       ret = lttng_register_trigger(trigger_b);
+       ok(ret == 0, "Registered second anonymous trigger");
+
+       ok(get_registered_triggers_count() == 2,
+                       "Trigger listing returns 2 trigger");
+       ok(unregister_all_triggers() == 2,
+                       "Successfully unregistered two anonymous triggers");
+
+end:
+       lttng_trigger_destroy(trigger_a);
+       lttng_trigger_destroy(trigger_b);
+}
+
+const test_function test_functions[] = {
+       register_anonymous_trigger,
+       register_named_trigger,
+       register_automatic_name_trigger,
+       double_register_anonymous_trigger,
+       double_register_named_trigger,
+       double_register_automatic_name_trigger,
+};
+
+int main(int argc, const char **argv)
+{
+       size_t i;
+
+       plan_tests(TEST_COUNT);
+
+       if (get_registered_triggers_count() != 0) {
+               fail("Session daemon already has registered triggers, bailing out");
+               goto end;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
+               const test_function fn = test_functions[i];
+
+               fn(UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING);
+               if (get_registered_triggers_count() != 0) {
+                       fail("Previous test left registered triggers, bailing out");
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
+               const test_function fn = test_functions[i];
+
+               fn(UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION);
+               if (get_registered_triggers_count() != 0) {
+                       fail("Previous test left registered triggers, bailing out");
+                       goto end;
+               }
+       }
+
+       register_multiple_anonymous_triggers();
+end:
+       return exit_status();
+}
index 21fb531122521e3e2ff079a14c8479eda017138b..dd3b0278fb507bd75560249742cd9339ede5fe1b 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 # SPDX-License-Identifier: GPL-2.0-only
 
-AM_CFLAGS += -I$(srcdir) -I$(top_srcdir)/tests/utils
+AM_CPPFLAGS += -I$(srcdir) -I$(top_srcdir)/tests/utils
 LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
 noinst_PROGRAMS = \
 LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
 noinst_PROGRAMS = \
@@ -11,7 +11,7 @@ notification_client_SOURCES = notification-client.c
 notification_client_LDADD = $(LIBLTTNG_CTL) \
        $(top_builddir)/tests/utils/libtestutils.la
 
 notification_client_LDADD = $(LIBLTTNG_CTL) \
        $(top_builddir)/tests/utils/libtestutils.la
 
-register_some_triggers_SOURCES = register-some-triggers.c
+register_some_triggers_SOURCES = register-some-triggers.cpp
 register_some_triggers_LDADD = $(LIBLTTNG_CTL) \
        $(top_builddir)/src/common/filter/libfilter.la \
        $(top_builddir)/src/common/bytecode/libbytecode.la
 register_some_triggers_LDADD = $(LIBLTTNG_CTL) \
        $(top_builddir)/src/common/filter/libfilter.la \
        $(top_builddir)/src/common/bytecode/libbytecode.la
diff --git a/tests/regression/tools/trigger/utils/register-some-triggers.c b/tests/regression/tools/trigger/utils/register-some-triggers.c
deleted file mode 100644 (file)
index 54eb783..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-/* Utility to register some triggers, for test purposes. */
-
-#include <common/filter/filter-ast.h>
-#include <common/macros.h>
-#include <lttng/lttng.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-static void register_trigger(const char *trigger_name,
-               struct lttng_condition *condition,
-               struct lttng_action *action)
-{
-       struct lttng_trigger *trigger;
-       enum lttng_error_code ret;
-
-       trigger = lttng_trigger_create(condition, action);
-       ret = lttng_register_trigger_with_name(trigger, trigger_name);
-       LTTNG_ASSERT(ret == LTTNG_OK);
-}
-
-/*
- * Register a trigger with the given condition and an action list containing a
- * single notify action.
- */
-static void register_trigger_action_list_notify(
-               const char *trigger_name, struct lttng_condition *condition)
-{
-       struct lttng_action *action_notify;
-       struct lttng_action *action_list;
-       enum lttng_action_status action_status;
-
-       action_list = lttng_action_list_create();
-       action_notify = lttng_action_notify_create();
-       action_status = lttng_action_list_add_action(
-                       action_list, action_notify);
-       LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-
-       register_trigger(trigger_name, condition, action_list);
-}
-
-static struct lttng_condition *create_session_consumed_size_condition(
-               const char *session_name, uint64_t threshold)
-{
-       struct lttng_condition *condition;
-       enum lttng_condition_status condition_status;
-
-       condition = lttng_condition_session_consumed_size_create();
-       condition_status =
-                       lttng_condition_session_consumed_size_set_session_name(
-                                       condition, session_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-       condition_status = lttng_condition_session_consumed_size_set_threshold(
-                       condition, threshold);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       return condition;
-}
-
-static void test_session_consumed_size_condition(void)
-{
-       register_trigger_action_list_notify(
-                       "trigger-with-session-consumed-size-condition",
-                       create_session_consumed_size_condition(
-                                       "the-session-name", 1234));
-}
-
-static void fill_buffer_usage_condition(struct lttng_condition *condition,
-               const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type)
-{
-       enum lttng_condition_status condition_status;
-
-       condition_status = lttng_condition_buffer_usage_set_session_name(
-                       condition, session_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-       condition_status = lttng_condition_buffer_usage_set_channel_name(
-                       condition, channel_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-       condition_status = lttng_condition_buffer_usage_set_domain_type(
-                       condition, domain_type);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static void fill_buffer_usage_bytes_condition(struct lttng_condition *condition,
-               const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type,
-               uint64_t threshold)
-{
-       enum lttng_condition_status condition_status;
-
-       fill_buffer_usage_condition(
-                       condition, session_name, channel_name, domain_type);
-       condition_status = lttng_condition_buffer_usage_set_threshold(
-                       condition, threshold);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static void fill_buffer_usage_ratio_condition(struct lttng_condition *condition,
-               const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type,
-               double ratio)
-{
-       enum lttng_condition_status condition_status;
-
-       fill_buffer_usage_condition(
-                       condition, session_name, channel_name, domain_type);
-       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
-                       condition, ratio);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static struct lttng_condition *create_buffer_usage_high_bytes_condition(
-               const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type,
-               uint64_t threshold)
-{
-       struct lttng_condition *condition;
-
-       condition = lttng_condition_buffer_usage_high_create();
-       fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
-                       domain_type, threshold);
-
-       return condition;
-}
-
-static struct lttng_condition *create_buffer_usage_low_bytes_condition(
-               const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type,
-               uint64_t threshold)
-{
-       struct lttng_condition *condition;
-
-       condition = lttng_condition_buffer_usage_low_create();
-       fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
-                       domain_type, threshold);
-
-       return condition;
-}
-
-static struct lttng_condition *create_buffer_usage_high_ratio_condition(
-               const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type,
-               double ratio)
-{
-       struct lttng_condition *condition;
-
-       condition = lttng_condition_buffer_usage_high_create();
-       fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
-                       domain_type, ratio);
-
-       return condition;
-}
-
-static struct lttng_condition *create_buffer_usage_low_ratio_condition(
-               const char *session_name,
-               const char *channel_name,
-               enum lttng_domain_type domain_type,
-               double ratio)
-{
-       struct lttng_condition *condition;
-
-       condition = lttng_condition_buffer_usage_low_create();
-       fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
-                       domain_type, ratio);
-
-       return condition;
-}
-
-static void test_buffer_usage_conditions(void)
-{
-       register_trigger_action_list_notify(
-                       "trigger-with-buffer-usage-high-bytes-condition",
-                       create_buffer_usage_high_bytes_condition(
-                                       "the-session-name", "the-channel-name",
-                                       LTTNG_DOMAIN_UST, 1234));
-
-       register_trigger_action_list_notify(
-                       "trigger-with-buffer-usage-low-bytes-condition",
-                       create_buffer_usage_low_bytes_condition(
-                                       "the-session-name", "the-channel-name",
-                                       LTTNG_DOMAIN_UST, 2345));
-
-       register_trigger_action_list_notify(
-                       "trigger-with-buffer-usage-high-ratio-condition",
-                       create_buffer_usage_high_ratio_condition(
-                                       "the-session-name", "the-channel-name",
-                                       LTTNG_DOMAIN_UST, 0.25));
-
-       register_trigger_action_list_notify(
-                       "trigger-with-buffer-usage-low-ratio-condition",
-                       create_buffer_usage_low_ratio_condition(
-                                       "the-session-name", "the-channel-name",
-                                       LTTNG_DOMAIN_UST, 0.4));
-}
-
-static void fill_session_rotation_condition(
-               struct lttng_condition *condition, const char *session_name)
-{
-       enum lttng_condition_status condition_status;
-
-       condition_status = lttng_condition_session_rotation_set_session_name(
-                       condition, session_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static struct lttng_condition *create_session_rotation_ongoing_condition(
-               const char *session_name)
-{
-       struct lttng_condition *condition;
-
-       condition = lttng_condition_session_rotation_ongoing_create();
-
-       fill_session_rotation_condition(condition, session_name);
-
-       return condition;
-}
-
-static struct lttng_condition *create_session_rotation_completed_condition(
-               const char *session_name)
-{
-       struct lttng_condition *condition;
-
-       condition = lttng_condition_session_rotation_completed_create();
-
-       fill_session_rotation_condition(condition, session_name);
-
-       return condition;
-}
-
-static void test_session_rotation_conditions(void)
-{
-       register_trigger_action_list_notify(
-                       "trigger-with-session-rotation-ongoing-condition",
-                       create_session_rotation_ongoing_condition(
-                                       "the-session-name"));
-
-       register_trigger_action_list_notify(
-                       "trigger-with-session-rotation-completed-condition",
-                       create_session_rotation_completed_condition(
-                                       "the-session-name"));
-}
-
-static struct {
-       const char *name;
-       void (*callback)(void);
-} tests[] = {
-               {
-                               "test_session_consumed_size_condition",
-                               test_session_consumed_size_condition,
-               },
-               {"test_buffer_usage_conditions", test_buffer_usage_conditions},
-               {"test_session_rotation_conditions",
-                               test_session_rotation_conditions},
-};
-
-static void show_known_tests(void)
-{
-       size_t i;
-
-       for (i = 0; i < ARRAY_SIZE(tests); i++) {
-               fprintf(stderr, " - %s\n", tests[i].name);
-       }
-}
-
-int main(int argc, char **argv)
-{
-       const char *test;
-       size_t i;
-       int ret;
-
-       if (argc != 2) {
-               fprintf(stderr, "Usage: %s <test>\n", argv[0]);
-               fprintf(stderr, "\n");
-               fprintf(stderr, "Test must be one of:\n");
-               show_known_tests();
-               goto error;
-       }
-
-       test = argv[1];
-
-       for (i = 0; i < ARRAY_SIZE(tests); i++) {
-               if (strcmp(tests[i].name, test) == 0) {
-                       break;
-               }
-       }
-
-       if (i == ARRAY_SIZE(tests)) {
-               fprintf(stderr, "Unrecognized test `%s`\n", test);
-               fprintf(stderr, "\n");
-               fprintf(stderr, "Known tests:\n");
-               show_known_tests();
-               goto error;
-       }
-
-       tests[i].callback();
-
-       ret = 0;
-       goto end;
-
-error:
-       ret = 1;
-
-end:
-       return ret;
-}
diff --git a/tests/regression/tools/trigger/utils/register-some-triggers.cpp b/tests/regression/tools/trigger/utils/register-some-triggers.cpp
new file mode 100644 (file)
index 0000000..54eb783
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+/* Utility to register some triggers, for test purposes. */
+
+#include <common/filter/filter-ast.h>
+#include <common/macros.h>
+#include <lttng/lttng.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+static void register_trigger(const char *trigger_name,
+               struct lttng_condition *condition,
+               struct lttng_action *action)
+{
+       struct lttng_trigger *trigger;
+       enum lttng_error_code ret;
+
+       trigger = lttng_trigger_create(condition, action);
+       ret = lttng_register_trigger_with_name(trigger, trigger_name);
+       LTTNG_ASSERT(ret == LTTNG_OK);
+}
+
+/*
+ * Register a trigger with the given condition and an action list containing a
+ * single notify action.
+ */
+static void register_trigger_action_list_notify(
+               const char *trigger_name, struct lttng_condition *condition)
+{
+       struct lttng_action *action_notify;
+       struct lttng_action *action_list;
+       enum lttng_action_status action_status;
+
+       action_list = lttng_action_list_create();
+       action_notify = lttng_action_notify_create();
+       action_status = lttng_action_list_add_action(
+                       action_list, action_notify);
+       LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
+
+       register_trigger(trigger_name, condition, action_list);
+}
+
+static struct lttng_condition *create_session_consumed_size_condition(
+               const char *session_name, uint64_t threshold)
+{
+       struct lttng_condition *condition;
+       enum lttng_condition_status condition_status;
+
+       condition = lttng_condition_session_consumed_size_create();
+       condition_status =
+                       lttng_condition_session_consumed_size_set_session_name(
+                                       condition, session_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+       condition_status = lttng_condition_session_consumed_size_set_threshold(
+                       condition, threshold);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       return condition;
+}
+
+static void test_session_consumed_size_condition(void)
+{
+       register_trigger_action_list_notify(
+                       "trigger-with-session-consumed-size-condition",
+                       create_session_consumed_size_condition(
+                                       "the-session-name", 1234));
+}
+
+static void fill_buffer_usage_condition(struct lttng_condition *condition,
+               const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type)
+{
+       enum lttng_condition_status condition_status;
+
+       condition_status = lttng_condition_buffer_usage_set_session_name(
+                       condition, session_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+       condition_status = lttng_condition_buffer_usage_set_channel_name(
+                       condition, channel_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+       condition_status = lttng_condition_buffer_usage_set_domain_type(
+                       condition, domain_type);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static void fill_buffer_usage_bytes_condition(struct lttng_condition *condition,
+               const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type,
+               uint64_t threshold)
+{
+       enum lttng_condition_status condition_status;
+
+       fill_buffer_usage_condition(
+                       condition, session_name, channel_name, domain_type);
+       condition_status = lttng_condition_buffer_usage_set_threshold(
+                       condition, threshold);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static void fill_buffer_usage_ratio_condition(struct lttng_condition *condition,
+               const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type,
+               double ratio)
+{
+       enum lttng_condition_status condition_status;
+
+       fill_buffer_usage_condition(
+                       condition, session_name, channel_name, domain_type);
+       condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+                       condition, ratio);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static struct lttng_condition *create_buffer_usage_high_bytes_condition(
+               const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type,
+               uint64_t threshold)
+{
+       struct lttng_condition *condition;
+
+       condition = lttng_condition_buffer_usage_high_create();
+       fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
+                       domain_type, threshold);
+
+       return condition;
+}
+
+static struct lttng_condition *create_buffer_usage_low_bytes_condition(
+               const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type,
+               uint64_t threshold)
+{
+       struct lttng_condition *condition;
+
+       condition = lttng_condition_buffer_usage_low_create();
+       fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
+                       domain_type, threshold);
+
+       return condition;
+}
+
+static struct lttng_condition *create_buffer_usage_high_ratio_condition(
+               const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type,
+               double ratio)
+{
+       struct lttng_condition *condition;
+
+       condition = lttng_condition_buffer_usage_high_create();
+       fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
+                       domain_type, ratio);
+
+       return condition;
+}
+
+static struct lttng_condition *create_buffer_usage_low_ratio_condition(
+               const char *session_name,
+               const char *channel_name,
+               enum lttng_domain_type domain_type,
+               double ratio)
+{
+       struct lttng_condition *condition;
+
+       condition = lttng_condition_buffer_usage_low_create();
+       fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
+                       domain_type, ratio);
+
+       return condition;
+}
+
+static void test_buffer_usage_conditions(void)
+{
+       register_trigger_action_list_notify(
+                       "trigger-with-buffer-usage-high-bytes-condition",
+                       create_buffer_usage_high_bytes_condition(
+                                       "the-session-name", "the-channel-name",
+                                       LTTNG_DOMAIN_UST, 1234));
+
+       register_trigger_action_list_notify(
+                       "trigger-with-buffer-usage-low-bytes-condition",
+                       create_buffer_usage_low_bytes_condition(
+                                       "the-session-name", "the-channel-name",
+                                       LTTNG_DOMAIN_UST, 2345));
+
+       register_trigger_action_list_notify(
+                       "trigger-with-buffer-usage-high-ratio-condition",
+                       create_buffer_usage_high_ratio_condition(
+                                       "the-session-name", "the-channel-name",
+                                       LTTNG_DOMAIN_UST, 0.25));
+
+       register_trigger_action_list_notify(
+                       "trigger-with-buffer-usage-low-ratio-condition",
+                       create_buffer_usage_low_ratio_condition(
+                                       "the-session-name", "the-channel-name",
+                                       LTTNG_DOMAIN_UST, 0.4));
+}
+
+static void fill_session_rotation_condition(
+               struct lttng_condition *condition, const char *session_name)
+{
+       enum lttng_condition_status condition_status;
+
+       condition_status = lttng_condition_session_rotation_set_session_name(
+                       condition, session_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static struct lttng_condition *create_session_rotation_ongoing_condition(
+               const char *session_name)
+{
+       struct lttng_condition *condition;
+
+       condition = lttng_condition_session_rotation_ongoing_create();
+
+       fill_session_rotation_condition(condition, session_name);
+
+       return condition;
+}
+
+static struct lttng_condition *create_session_rotation_completed_condition(
+               const char *session_name)
+{
+       struct lttng_condition *condition;
+
+       condition = lttng_condition_session_rotation_completed_create();
+
+       fill_session_rotation_condition(condition, session_name);
+
+       return condition;
+}
+
+static void test_session_rotation_conditions(void)
+{
+       register_trigger_action_list_notify(
+                       "trigger-with-session-rotation-ongoing-condition",
+                       create_session_rotation_ongoing_condition(
+                                       "the-session-name"));
+
+       register_trigger_action_list_notify(
+                       "trigger-with-session-rotation-completed-condition",
+                       create_session_rotation_completed_condition(
+                                       "the-session-name"));
+}
+
+static struct {
+       const char *name;
+       void (*callback)(void);
+} tests[] = {
+               {
+                               "test_session_consumed_size_condition",
+                               test_session_consumed_size_condition,
+               },
+               {"test_buffer_usage_conditions", test_buffer_usage_conditions},
+               {"test_session_rotation_conditions",
+                               test_session_rotation_conditions},
+};
+
+static void show_known_tests(void)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(tests); i++) {
+               fprintf(stderr, " - %s\n", tests[i].name);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       const char *test;
+       size_t i;
+       int ret;
+
+       if (argc != 2) {
+               fprintf(stderr, "Usage: %s <test>\n", argv[0]);
+               fprintf(stderr, "\n");
+               fprintf(stderr, "Test must be one of:\n");
+               show_known_tests();
+               goto error;
+       }
+
+       test = argv[1];
+
+       for (i = 0; i < ARRAY_SIZE(tests); i++) {
+               if (strcmp(tests[i].name, test) == 0) {
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(tests)) {
+               fprintf(stderr, "Unrecognized test `%s`\n", test);
+               fprintf(stderr, "\n");
+               fprintf(stderr, "Known tests:\n");
+               show_known_tests();
+               goto error;
+       }
+
+       tests[i].callback();
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       return ret;
+}
index 1c7c953264ba66d8429d6b03aca3373df4eb96b8..96dbe28523693488d72c2442809db3bd2da266ee 100644 (file)
@@ -7,7 +7,9 @@ EXTRA_DIST = utils.sh test_utils.py babelstats.pl warn_processes.sh \
 dist_noinst_SCRIPTS = utils.sh test_utils.py babelstats.pl tap-driver.sh
 noinst_LTLIBRARIES = libtestutils.la
 
 dist_noinst_SCRIPTS = utils.sh test_utils.py babelstats.pl tap-driver.sh
 noinst_LTLIBRARIES = libtestutils.la
 
-libtestutils_la_SOURCES = utils.c utils.h
+libtestutils_la_SOURCES = \
+       utils.cpp \
+       utils.h
 
 all-local:
        @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
 
 all-local:
        @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
index adc76ee522ad3cb32008b9a69831d8d58b8a1b21..5c1cddefeb09917e862c7b994ac084a05adc7987 100644 (file)
@@ -4,7 +4,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/tests/utils -I$(srcdir) \
               -I$(top_srcdir)/tests/utils/testapp
 
 noinst_PROGRAMS = gen-ns-events
               -I$(top_srcdir)/tests/utils/testapp
 
 noinst_PROGRAMS = gen-ns-events
-gen_ns_events_SOURCES = gen-ns-events.c
+gen_ns_events_SOURCES = gen-ns-events.cpp
 gen_ns_events_LDADD = \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS) $(POPT_LIBS)
 gen_ns_events_LDADD = \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS) $(POPT_LIBS)
diff --git a/tests/utils/testapp/gen-ns-events/gen-ns-events.c b/tests/utils/testapp/gen-ns-events/gen-ns-events.c
deleted file mode 100644 (file)
index 7c2b647..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <popt.h>
-#include <sched.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/tid.h>
-
-#include "signal-helper.h"
-#include "utils.h"
-
-#define LTTNG_PROC_NS_PATH_MAX 40
-
-/*
- * The runner of this test validates that the kernel supports the
- * namespace for which it is invoked. However, these defines are added
- * to allow tests to run on systems that support a given namespace,
- * but that use a libc that doesn't define its associated clone flag.
- */
-#ifndef CLONE_NEWNS
-#define CLONE_NEWNS     0x00020000
-#endif
-#ifndef CLONE_NEWCGROUP
-#define CLONE_NEWCGROUP 0x02000000
-#endif
-#ifndef CLONE_NEWUTS
-#define CLONE_NEWUTS    0x04000000
-#endif
-#ifndef CLONE_NEWIPC
-#define CLONE_NEWIPC    0x08000000
-#endif
-#ifndef CLONE_NEWUSER
-#define CLONE_NEWUSER   0x10000000
-#endif
-#ifndef CLONE_NEWPID
-#define CLONE_NEWPID    0x20000000
-#endif
-#ifndef CLONE_NEWNET
-#define CLONE_NEWNET    0x40000000
-#endif
-#ifndef CLONE_NEWTIME
-#define CLONE_NEWTIME   0x00000080
-#endif
-
-static int debug = 0;
-static char *ns_opt = NULL;
-static char *before_unshare_wait_file_path = NULL;
-static char *after_unshare_wait_file_path = NULL;
-static char *after_unshare_signal_file_path = NULL;
-
-static struct poptOption opts[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
-       { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
-       { "before", 'b', POPT_ARG_STRING, &before_unshare_wait_file_path, 0, "Wait for file before unshare", NULL },
-       { "after", 'a', POPT_ARG_STRING, &after_unshare_wait_file_path, 0, "Wait for file after unshare", NULL },
-       { "signal", 's', POPT_ARG_STRING, &after_unshare_signal_file_path, 0, "Create signal file after unshare", NULL },
-       POPT_AUTOHELP
-       { NULL, 0, 0, NULL, 0 }
-};
-
-static void debug_printf(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-
-       if (debug) {
-               vfprintf(stderr, format, args);
-       }
-
-       va_end(args);
-}
-
-static int get_ns_inum(const char *ns, ino_t *ns_inum)
-{
-       int ret = 0;
-       struct stat sb;
-       char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
-
-       /*
-        * /proc/thread-self was introduced in kernel v3.17
-        */
-       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
-                       "/proc/thread-self/ns/%s", ns) >= 0) {
-               if (stat(proc_ns_path, &sb) == 0) {
-                       *ns_inum = sb.st_ino;
-               } else {
-                       ret = -1;
-               }
-               goto end;
-       }
-
-       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
-                       "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
-               if (stat(proc_ns_path, &sb) == 0) {
-                       *ns_inum = sb.st_ino;
-               } else {
-                       ret = -1;
-               }
-               goto end;
-       }
-end:
-       return ret;
-}
-
-static int do_the_needful(int ns_flag, const char *ns_str)
-{
-       int ret = 0;
-       ino_t ns1, ns2;
-
-       ret = get_ns_inum(ns_str, &ns1);
-       if (ret) {
-               debug_printf("Failed to get ns inode number for namespace %s",
-                               ns_str);
-               ret = -1;
-               goto end;
-       }
-       debug_printf("Initial %s ns inode number:      %lu\n", ns_str, ns1);
-
-       /* Wait on synchronization before unshare. */
-       if (before_unshare_wait_file_path) {
-               ret = wait_on_file(before_unshare_wait_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-
-       ret = unshare(ns_flag);
-       if (ret == -1) {
-               perror("Failed to unshare namespace");
-               goto end;
-       }
-
-       ret = get_ns_inum(ns_str, &ns2);
-       if (ret) {
-               debug_printf("Failed to get ns inode number for namespace %s",
-                               ns_str);
-               ret = -1;
-               goto end;
-       }
-       debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
-
-       /* Signal that the unshare call is completed. */
-       if (after_unshare_signal_file_path) {
-               ret = create_file(after_unshare_signal_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-
-       /* Wait on synchronization after unshare. */
-       if (after_unshare_wait_file_path) {
-               ret = wait_on_file(after_unshare_wait_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-int main(int argc, const char **argv)
-{
-       int opt;
-       int ret = EXIT_SUCCESS;
-       poptContext pc;
-
-       pc = poptGetContext(NULL, argc, argv, opts, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       if (argc < 2) {
-               poptPrintHelp(pc, stderr, 0);
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       while ((opt = poptGetNextOpt(pc)) >= 0) {
-               switch (opt) {
-               default:
-                       poptPrintUsage(pc, stderr, 0);
-                       ret = EXIT_FAILURE;
-                       goto end;
-               }
-       }
-
-       if (opt < -1) {
-               /* an error occurred during option processing */
-               poptPrintUsage(pc, stderr, 0);
-               fprintf(stderr, "%s: %s\n",
-                       poptBadOption(pc, POPT_BADOPTION_NOALIAS),
-                       poptStrerror(opt));
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       if (ns_opt == NULL) {
-               poptPrintUsage(pc, stderr, 0);
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       if (set_signal_handler()) {
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       if (strncmp(ns_opt, "cgroup", 6) == 0) {
-               ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
-       } else if (strncmp(ns_opt, "ipc", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWIPC, "ipc");
-       } else if (strncmp(ns_opt, "mnt", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWNS, "mnt");
-       } else if (strncmp(ns_opt, "net", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWNET, "net");
-       } else if (strncmp(ns_opt, "pid", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWPID, "pid");
-       } else if (strncmp(ns_opt, "time", 4) == 0) {
-               ret = do_the_needful(CLONE_NEWTIME, "time");
-       } else if (strncmp(ns_opt, "user", 4) == 0) {
-               /*
-                * Will always fail, requires a single threaded application,
-                * which can't happen with UST.
-                */
-               ret = do_the_needful(CLONE_NEWUSER, "user");
-       } else if (strncmp(ns_opt, "uts", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWUTS, "uts");
-       } else {
-               printf("invalid ns id\n");
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-       ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
-end:
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/tests/utils/testapp/gen-ns-events/gen-ns-events.cpp b/tests/utils/testapp/gen-ns-events/gen-ns-events.cpp
new file mode 100644 (file)
index 0000000..7c2b647
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <popt.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/tid.h>
+
+#include "signal-helper.h"
+#include "utils.h"
+
+#define LTTNG_PROC_NS_PATH_MAX 40
+
+/*
+ * The runner of this test validates that the kernel supports the
+ * namespace for which it is invoked. However, these defines are added
+ * to allow tests to run on systems that support a given namespace,
+ * but that use a libc that doesn't define its associated clone flag.
+ */
+#ifndef CLONE_NEWNS
+#define CLONE_NEWNS     0x00020000
+#endif
+#ifndef CLONE_NEWCGROUP
+#define CLONE_NEWCGROUP 0x02000000
+#endif
+#ifndef CLONE_NEWUTS
+#define CLONE_NEWUTS    0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+#define CLONE_NEWIPC    0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+#define CLONE_NEWUSER   0x10000000
+#endif
+#ifndef CLONE_NEWPID
+#define CLONE_NEWPID    0x20000000
+#endif
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET    0x40000000
+#endif
+#ifndef CLONE_NEWTIME
+#define CLONE_NEWTIME   0x00000080
+#endif
+
+static int debug = 0;
+static char *ns_opt = NULL;
+static char *before_unshare_wait_file_path = NULL;
+static char *after_unshare_wait_file_path = NULL;
+static char *after_unshare_signal_file_path = NULL;
+
+static struct poptOption opts[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
+       { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
+       { "before", 'b', POPT_ARG_STRING, &before_unshare_wait_file_path, 0, "Wait for file before unshare", NULL },
+       { "after", 'a', POPT_ARG_STRING, &after_unshare_wait_file_path, 0, "Wait for file after unshare", NULL },
+       { "signal", 's', POPT_ARG_STRING, &after_unshare_signal_file_path, 0, "Create signal file after unshare", NULL },
+       POPT_AUTOHELP
+       { NULL, 0, 0, NULL, 0 }
+};
+
+static void debug_printf(const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+
+       if (debug) {
+               vfprintf(stderr, format, args);
+       }
+
+       va_end(args);
+}
+
+static int get_ns_inum(const char *ns, ino_t *ns_inum)
+{
+       int ret = 0;
+       struct stat sb;
+       char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
+
+       /*
+        * /proc/thread-self was introduced in kernel v3.17
+        */
+       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+                       "/proc/thread-self/ns/%s", ns) >= 0) {
+               if (stat(proc_ns_path, &sb) == 0) {
+                       *ns_inum = sb.st_ino;
+               } else {
+                       ret = -1;
+               }
+               goto end;
+       }
+
+       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+                       "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
+               if (stat(proc_ns_path, &sb) == 0) {
+                       *ns_inum = sb.st_ino;
+               } else {
+                       ret = -1;
+               }
+               goto end;
+       }
+end:
+       return ret;
+}
+
+static int do_the_needful(int ns_flag, const char *ns_str)
+{
+       int ret = 0;
+       ino_t ns1, ns2;
+
+       ret = get_ns_inum(ns_str, &ns1);
+       if (ret) {
+               debug_printf("Failed to get ns inode number for namespace %s",
+                               ns_str);
+               ret = -1;
+               goto end;
+       }
+       debug_printf("Initial %s ns inode number:      %lu\n", ns_str, ns1);
+
+       /* Wait on synchronization before unshare. */
+       if (before_unshare_wait_file_path) {
+               ret = wait_on_file(before_unshare_wait_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+
+       ret = unshare(ns_flag);
+       if (ret == -1) {
+               perror("Failed to unshare namespace");
+               goto end;
+       }
+
+       ret = get_ns_inum(ns_str, &ns2);
+       if (ret) {
+               debug_printf("Failed to get ns inode number for namespace %s",
+                               ns_str);
+               ret = -1;
+               goto end;
+       }
+       debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
+
+       /* Signal that the unshare call is completed. */
+       if (after_unshare_signal_file_path) {
+               ret = create_file(after_unshare_signal_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+
+       /* Wait on synchronization after unshare. */
+       if (after_unshare_wait_file_path) {
+               ret = wait_on_file(after_unshare_wait_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+int main(int argc, const char **argv)
+{
+       int opt;
+       int ret = EXIT_SUCCESS;
+       poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, opts, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       if (argc < 2) {
+               poptPrintHelp(pc, stderr, 0);
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       while ((opt = poptGetNextOpt(pc)) >= 0) {
+               switch (opt) {
+               default:
+                       poptPrintUsage(pc, stderr, 0);
+                       ret = EXIT_FAILURE;
+                       goto end;
+               }
+       }
+
+       if (opt < -1) {
+               /* an error occurred during option processing */
+               poptPrintUsage(pc, stderr, 0);
+               fprintf(stderr, "%s: %s\n",
+                       poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+                       poptStrerror(opt));
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       if (ns_opt == NULL) {
+               poptPrintUsage(pc, stderr, 0);
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       if (set_signal_handler()) {
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       if (strncmp(ns_opt, "cgroup", 6) == 0) {
+               ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
+       } else if (strncmp(ns_opt, "ipc", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWIPC, "ipc");
+       } else if (strncmp(ns_opt, "mnt", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWNS, "mnt");
+       } else if (strncmp(ns_opt, "net", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWNET, "net");
+       } else if (strncmp(ns_opt, "pid", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWPID, "pid");
+       } else if (strncmp(ns_opt, "time", 4) == 0) {
+               ret = do_the_needful(CLONE_NEWTIME, "time");
+       } else if (strncmp(ns_opt, "user", 4) == 0) {
+               /*
+                * Will always fail, requires a single threaded application,
+                * which can't happen with UST.
+                */
+               ret = do_the_needful(CLONE_NEWUSER, "user");
+       } else if (strncmp(ns_opt, "uts", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWUTS, "uts");
+       } else {
+               printf("invalid ns id\n");
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+       ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
+end:
+       poptFreeContext(pc);
+       return ret;
+}
index 3f3a77fa7da019d18af35457a34790a10d455446..59ac2f3a990fe563016c223e580d02c5705fa150 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 # SPDX-License-Identifier: GPL-2.0-only
 
-AM_CFLAGS += -I$(top_srcdir)/tests/utils/
+AM_CPPFLAGS += -I$(top_srcdir)/tests/utils
 
 noinst_PROGRAMS = gen-syscall-events
 
 noinst_PROGRAMS = gen-syscall-events
-gen_syscall_events_SOURCES = gen-syscall-events.c
+gen_syscall_events_SOURCES = gen-syscall-events.cpp
 gen_syscall_events_LDADD = $(top_builddir)/tests/utils/libtestutils.la
 gen_syscall_events_LDADD = $(top_builddir)/tests/utils/libtestutils.la
diff --git a/tests/utils/testapp/gen-syscall-events/gen-syscall-events.c b/tests/utils/testapp/gen-syscall-events/gen-syscall-events.c
deleted file mode 100644 (file)
index 6a24686..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2017 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include <common/error.h>
-#include <common/align.h>
-
-#include "utils.h"
-
-#define MAX_LEN 16
-
-/*
- * The LTTng system call tracing facilities can't handle page faults at the
- * moment. If a fault would occur while reading a syscall argument, the
- * tracer will report an empty string (""). Since the proper execution of the
- * tests which use this generator depends on some syscall string arguments being
- * present, this util allows us to mitigate the page-fault risk.
- *
- * This isn't a proper fix; it is simply the best we can do for now.
- * See bug #1261 for more context.
- */
-static
-void prefault_string(const char *p)
-{
-       const char * const end = p + strlen(p) + 1;
-
-       while (p < end) {
-               /*
-                * Trigger a read attempt on *p, faulting-in the pages
-                * for reading.
-                */
-               asm volatile("" : : "m"(*p));
-               p += sysconf(_SC_PAGE_SIZE);
-       }
-}
-
-static
-int open_read_close(const char *path)
-{
-       int fd, ret;
-       char buf[MAX_LEN];
-
-       /*
-        * Start generating syscalls. We use syscall(2) to prevent libc from
-        * changing the underlying syscall (e.g. calling openat(2) instead of
-        * open(2)).
-        */
-       prefault_string(path);
-       fd = syscall(SYS_openat, AT_FDCWD, path, O_RDONLY);
-       if (fd < 0) {
-               PERROR_NO_LOGGER("Failed to open file with openat(): path = '%s'", path);
-               ret = -1;
-               goto error;
-       }
-
-       ret = syscall(SYS_read, fd, buf, MAX_LEN);
-       if (ret < 0) {
-               PERROR_NO_LOGGER("Failed to read file: path = '%s', fd = %d, length = %d",
-                               path, fd, MAX_LEN);
-               ret = -1;
-               goto error;
-       }
-
-       ret = syscall(SYS_close, fd);
-       if (ret == -1) {
-               PERROR_NO_LOGGER("Failed to close file: path = '%s', fd = %d", path, fd);
-               ret = -1;
-               goto error;
-       }
-
-error:
-       return ret;
-}
-
-/*
- * The process waits for the creation of a file passed as argument from an
- * external processes to execute a syscall and exiting. This is useful for tests
- * in combinaison with LTTng's PID tracker feature where we can trace the kernel
- * events generated by our test process only.
- */
-int main(int argc, char **argv)
-{
-       int ret;
-       const char *start_file, *path1, *path2;
-
-       if (argc != 4) {
-               fprintf(stderr, "Error: Missing argument\n");
-               fprintf(stderr, "USAGE: %s PATH_WAIT_FILE PATH1_TO_OPEN PATH2_TO_OPEN\n", argv[0]);
-               ret = -1;
-               goto error;
-       }
-
-       start_file = argv[1];
-       path1 = argv[2];
-       path2 = argv[3];
-
-       /*
-        * Wait for the start_file to be created by an external process
-        * (typically the test script) before executing the syscalls.
-        */
-       ret = wait_on_file(start_file);
-       if (ret != 0) {
-               goto error;
-       }
-
-       /*
-        * Start generating syscalls. We use syscall(2) to prevent libc to change
-        * the underlying syscall. e.g. calling openat(2) instead of open(2).
-        */
-       ret = open_read_close(path1);
-       if (ret == -1) {
-               ret = -1;
-               goto error;
-       }
-
-       ret = open_read_close(path2);
-       if (ret == -1) {
-               ret = -1;
-               goto error;
-       }
-
-error:
-       return ret;
-}
diff --git a/tests/utils/testapp/gen-syscall-events/gen-syscall-events.cpp b/tests/utils/testapp/gen-syscall-events/gen-syscall-events.cpp
new file mode 100644 (file)
index 0000000..6a24686
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <common/error.h>
+#include <common/align.h>
+
+#include "utils.h"
+
+#define MAX_LEN 16
+
+/*
+ * The LTTng system call tracing facilities can't handle page faults at the
+ * moment. If a fault would occur while reading a syscall argument, the
+ * tracer will report an empty string (""). Since the proper execution of the
+ * tests which use this generator depends on some syscall string arguments being
+ * present, this util allows us to mitigate the page-fault risk.
+ *
+ * This isn't a proper fix; it is simply the best we can do for now.
+ * See bug #1261 for more context.
+ */
+static
+void prefault_string(const char *p)
+{
+       const char * const end = p + strlen(p) + 1;
+
+       while (p < end) {
+               /*
+                * Trigger a read attempt on *p, faulting-in the pages
+                * for reading.
+                */
+               asm volatile("" : : "m"(*p));
+               p += sysconf(_SC_PAGE_SIZE);
+       }
+}
+
+static
+int open_read_close(const char *path)
+{
+       int fd, ret;
+       char buf[MAX_LEN];
+
+       /*
+        * Start generating syscalls. We use syscall(2) to prevent libc from
+        * changing the underlying syscall (e.g. calling openat(2) instead of
+        * open(2)).
+        */
+       prefault_string(path);
+       fd = syscall(SYS_openat, AT_FDCWD, path, O_RDONLY);
+       if (fd < 0) {
+               PERROR_NO_LOGGER("Failed to open file with openat(): path = '%s'", path);
+               ret = -1;
+               goto error;
+       }
+
+       ret = syscall(SYS_read, fd, buf, MAX_LEN);
+       if (ret < 0) {
+               PERROR_NO_LOGGER("Failed to read file: path = '%s', fd = %d, length = %d",
+                               path, fd, MAX_LEN);
+               ret = -1;
+               goto error;
+       }
+
+       ret = syscall(SYS_close, fd);
+       if (ret == -1) {
+               PERROR_NO_LOGGER("Failed to close file: path = '%s', fd = %d", path, fd);
+               ret = -1;
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
+/*
+ * The process waits for the creation of a file passed as argument from an
+ * external processes to execute a syscall and exiting. This is useful for tests
+ * in combinaison with LTTng's PID tracker feature where we can trace the kernel
+ * events generated by our test process only.
+ */
+int main(int argc, char **argv)
+{
+       int ret;
+       const char *start_file, *path1, *path2;
+
+       if (argc != 4) {
+               fprintf(stderr, "Error: Missing argument\n");
+               fprintf(stderr, "USAGE: %s PATH_WAIT_FILE PATH1_TO_OPEN PATH2_TO_OPEN\n", argv[0]);
+               ret = -1;
+               goto error;
+       }
+
+       start_file = argv[1];
+       path1 = argv[2];
+       path2 = argv[3];
+
+       /*
+        * Wait for the start_file to be created by an external process
+        * (typically the test script) before executing the syscalls.
+        */
+       ret = wait_on_file(start_file);
+       if (ret != 0) {
+               goto error;
+       }
+
+       /*
+        * Start generating syscalls. We use syscall(2) to prevent libc to change
+        * the underlying syscall. e.g. calling openat(2) instead of open(2).
+        */
+       ret = open_read_close(path1);
+       if (ret == -1) {
+               ret = -1;
+               goto error;
+       }
+
+       ret = open_read_close(path2);
+       if (ret == -1) {
+               ret = -1;
+               goto error;
+       }
+
+error:
+       return ret;
+}
index 35e6d67008f87b7b9cc0d6f0841544ea362ba4a7..2e3ad0747ff767f512df37fefc1515f1d177565b 100644 (file)
@@ -5,7 +5,10 @@ AM_CPPFLAGS += -I$(top_srcdir)/tests/utils -I$(srcdir) \
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-events-ns
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-events-ns
-gen_ust_events_ns_SOURCES = gen-ust-events-ns.c tp.c tp.h
+gen_ust_events_ns_SOURCES = \
+       gen-ust-events-ns.cpp \
+       tp.c \
+       tp.h
 gen_ust_events_ns_LDADD = $(UST_LIBS) -llttng-ust-fork \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS) $(POPT_LIBS)
 gen_ust_events_ns_LDADD = $(UST_LIBS) -llttng-ust-fork \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS) $(POPT_LIBS)
diff --git a/tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns.c b/tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns.c
deleted file mode 100644 (file)
index dadfc3d..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <popt.h>
-#include <sched.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/tid.h>
-
-#include "signal-helper.h"
-#include "utils.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-#define LTTNG_PROC_NS_PATH_MAX 40
-
-/*
- * The runner of this test validates that the kernel supports the
- * namespace for which it is invoked. However, these defines are added
- * to allow tests to run on systems that support a given namespace,
- * but that use a libc that doesn't define its associated clone flag.
- */
-#ifndef CLONE_NEWNS
-#define CLONE_NEWNS     0x00020000
-#endif
-#ifndef CLONE_NEWCGROUP
-#define CLONE_NEWCGROUP 0x02000000
-#endif
-#ifndef CLONE_NEWUTS
-#define CLONE_NEWUTS    0x04000000
-#endif
-#ifndef CLONE_NEWIPC
-#define CLONE_NEWIPC    0x08000000
-#endif
-#ifndef CLONE_NEWUSER
-#define CLONE_NEWUSER   0x10000000
-#endif
-#ifndef CLONE_NEWPID
-#define CLONE_NEWPID    0x20000000
-#endif
-#ifndef CLONE_NEWNET
-#define CLONE_NEWNET    0x40000000
-#endif
-#ifndef CLONE_NEWTIME
-#define CLONE_NEWTIME   0x00000080
-#endif
-
-static int nr_iter = 100;
-static int debug = 0;
-static char *ns_opt = NULL;
-static char *after_unshare_file_path = NULL;
-static char *before_second_event_file_path = NULL;
-
-static
-struct poptOption opts[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
-       { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
-       { "iter", 'i', POPT_ARG_INT, &nr_iter, 0, "Number of tracepoint iterations", NULL },
-       { "after", 'a', POPT_ARG_STRING, &after_unshare_file_path, 0, "after_unshare_file_path,", NULL },
-       { "before", 'b', POPT_ARG_STRING, &before_second_event_file_path, 0, "before_second_event_file_path,", NULL },
-       POPT_AUTOHELP
-       { NULL, 0, 0, NULL, 0 }
-};
-
-static void debug_printf(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-
-       if (debug) {
-               vfprintf(stderr, format, args);
-       }
-
-       va_end(args);
-}
-
-static int get_ns_inum(const char *ns, ino_t *ns_inum)
-{
-       int ret = -1;
-       struct stat sb;
-       char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
-
-       /*
-        * /proc/thread-self was introduced in kernel v3.17
-        */
-       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
-                       "/proc/thread-self/ns/%s", ns) >= 0) {
-               if (stat(proc_ns_path, &sb) == 0) {
-                       *ns_inum = sb.st_ino;
-                       ret = 0;
-               }
-               goto end;
-       }
-
-       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
-                       "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
-               if (stat(proc_ns_path, &sb) == 0) {
-                       *ns_inum = sb.st_ino;
-                       ret = 0;
-               }
-               goto end;
-       }
-end:
-       return ret;
-}
-
-static int do_the_needful(int ns_flag, const char *ns_str)
-{
-       int ret = 0, i;
-       ino_t ns1, ns2;
-
-       ret = get_ns_inum(ns_str, &ns1);
-       if (ret) {
-               debug_printf("Failed to get ns inode number for namespace %s",
-                               ns_str);
-               ret = -1;
-               goto end;
-       }
-       debug_printf("Initial %s ns inode number:      %lu\n", ns_str, ns1);
-
-       for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
-               tracepoint(tp, tptest, ns1);
-               if (should_quit) {
-                       break;
-               }
-       }
-
-       ret = unshare(ns_flag);
-       if (ret == -1) {
-               perror("Failed to unshare namespace");
-               goto end;
-       }
-
-       ret = get_ns_inum(ns_str, &ns2);
-       if (ret) {
-               debug_printf("Failed to get ns inode number for namespace %s",
-                               ns_str);
-               ret = -1;
-               goto end;
-       }
-       debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
-
-       /*
-        * Signal that we emited the first event group and that the
-        * unshare call is completed.
-        */
-       if (after_unshare_file_path) {
-               ret = create_file(after_unshare_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-
-       /* Wait on synchronization before writing second event group. */
-       if (before_second_event_file_path) {
-               ret = wait_on_file(before_second_event_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-
-       for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
-               tracepoint(tp, tptest, ns2);
-               if (should_quit) {
-                       break;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Send X events, change NS, wait for file to sync with test script, send X
- * events in new NS
- */
-int main(int argc, const char **argv)
-{
-       int opt;
-       int ret = EXIT_SUCCESS;
-       poptContext pc;
-
-       pc = poptGetContext(NULL, argc, argv, opts, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       if (argc < 2) {
-               poptPrintHelp(pc, stderr, 0);
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       while ((opt = poptGetNextOpt(pc)) >= 0) {
-               switch (opt) {
-               default:
-                       poptPrintUsage(pc, stderr, 0);
-                       ret = EXIT_FAILURE;
-                       goto end;
-               }
-       }
-
-       if (opt < -1) {
-               /* An error occurred during option processing. */
-               poptPrintUsage(pc, stderr, 0);
-               fprintf(stderr, "%s: %s\n",
-                               poptBadOption(pc, POPT_BADOPTION_NOALIAS),
-                               poptStrerror(opt));
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       if (ns_opt == NULL) {
-               poptPrintUsage(pc, stderr, 0);
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       if (set_signal_handler()) {
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-
-       if (strncmp(ns_opt, "cgroup", 6) == 0) {
-               ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
-       } else if (strncmp(ns_opt, "ipc", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWIPC, "ipc");
-       } else if (strncmp(ns_opt, "mnt", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWNS, "mnt");
-       } else if (strncmp(ns_opt, "net", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWNET, "net");
-       } else if (strncmp(ns_opt, "pid", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWPID, "pid");
-       } else if (strncmp(ns_opt, "time", 4) == 0) {
-               ret = do_the_needful(CLONE_NEWTIME, "time");
-       } else if (strncmp(ns_opt, "user", 4) == 0) {
-               /*
-                * Will always fail, requires a single threaded application,
-                * which can't happen with UST.
-                */
-               ret = do_the_needful(CLONE_NEWUSER, "user");
-       } else if (strncmp(ns_opt, "uts", 3) == 0) {
-               ret = do_the_needful(CLONE_NEWUTS, "uts");
-       } else {
-               printf("invalid ns id\n");
-               ret = EXIT_FAILURE;
-               goto end;
-       }
-       ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
-end:
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns.cpp b/tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns.cpp
new file mode 100644 (file)
index 0000000..dadfc3d
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <popt.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/tid.h>
+
+#include "signal-helper.h"
+#include "utils.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+#define LTTNG_PROC_NS_PATH_MAX 40
+
+/*
+ * The runner of this test validates that the kernel supports the
+ * namespace for which it is invoked. However, these defines are added
+ * to allow tests to run on systems that support a given namespace,
+ * but that use a libc that doesn't define its associated clone flag.
+ */
+#ifndef CLONE_NEWNS
+#define CLONE_NEWNS     0x00020000
+#endif
+#ifndef CLONE_NEWCGROUP
+#define CLONE_NEWCGROUP 0x02000000
+#endif
+#ifndef CLONE_NEWUTS
+#define CLONE_NEWUTS    0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+#define CLONE_NEWIPC    0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+#define CLONE_NEWUSER   0x10000000
+#endif
+#ifndef CLONE_NEWPID
+#define CLONE_NEWPID    0x20000000
+#endif
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET    0x40000000
+#endif
+#ifndef CLONE_NEWTIME
+#define CLONE_NEWTIME   0x00000080
+#endif
+
+static int nr_iter = 100;
+static int debug = 0;
+static char *ns_opt = NULL;
+static char *after_unshare_file_path = NULL;
+static char *before_second_event_file_path = NULL;
+
+static
+struct poptOption opts[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
+       { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
+       { "iter", 'i', POPT_ARG_INT, &nr_iter, 0, "Number of tracepoint iterations", NULL },
+       { "after", 'a', POPT_ARG_STRING, &after_unshare_file_path, 0, "after_unshare_file_path,", NULL },
+       { "before", 'b', POPT_ARG_STRING, &before_second_event_file_path, 0, "before_second_event_file_path,", NULL },
+       POPT_AUTOHELP
+       { NULL, 0, 0, NULL, 0 }
+};
+
+static void debug_printf(const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+
+       if (debug) {
+               vfprintf(stderr, format, args);
+       }
+
+       va_end(args);
+}
+
+static int get_ns_inum(const char *ns, ino_t *ns_inum)
+{
+       int ret = -1;
+       struct stat sb;
+       char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
+
+       /*
+        * /proc/thread-self was introduced in kernel v3.17
+        */
+       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+                       "/proc/thread-self/ns/%s", ns) >= 0) {
+               if (stat(proc_ns_path, &sb) == 0) {
+                       *ns_inum = sb.st_ino;
+                       ret = 0;
+               }
+               goto end;
+       }
+
+       if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+                       "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
+               if (stat(proc_ns_path, &sb) == 0) {
+                       *ns_inum = sb.st_ino;
+                       ret = 0;
+               }
+               goto end;
+       }
+end:
+       return ret;
+}
+
+static int do_the_needful(int ns_flag, const char *ns_str)
+{
+       int ret = 0, i;
+       ino_t ns1, ns2;
+
+       ret = get_ns_inum(ns_str, &ns1);
+       if (ret) {
+               debug_printf("Failed to get ns inode number for namespace %s",
+                               ns_str);
+               ret = -1;
+               goto end;
+       }
+       debug_printf("Initial %s ns inode number:      %lu\n", ns_str, ns1);
+
+       for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
+               tracepoint(tp, tptest, ns1);
+               if (should_quit) {
+                       break;
+               }
+       }
+
+       ret = unshare(ns_flag);
+       if (ret == -1) {
+               perror("Failed to unshare namespace");
+               goto end;
+       }
+
+       ret = get_ns_inum(ns_str, &ns2);
+       if (ret) {
+               debug_printf("Failed to get ns inode number for namespace %s",
+                               ns_str);
+               ret = -1;
+               goto end;
+       }
+       debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
+
+       /*
+        * Signal that we emited the first event group and that the
+        * unshare call is completed.
+        */
+       if (after_unshare_file_path) {
+               ret = create_file(after_unshare_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+
+       /* Wait on synchronization before writing second event group. */
+       if (before_second_event_file_path) {
+               ret = wait_on_file(before_second_event_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
+               tracepoint(tp, tptest, ns2);
+               if (should_quit) {
+                       break;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Send X events, change NS, wait for file to sync with test script, send X
+ * events in new NS
+ */
+int main(int argc, const char **argv)
+{
+       int opt;
+       int ret = EXIT_SUCCESS;
+       poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, opts, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       if (argc < 2) {
+               poptPrintHelp(pc, stderr, 0);
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       while ((opt = poptGetNextOpt(pc)) >= 0) {
+               switch (opt) {
+               default:
+                       poptPrintUsage(pc, stderr, 0);
+                       ret = EXIT_FAILURE;
+                       goto end;
+               }
+       }
+
+       if (opt < -1) {
+               /* An error occurred during option processing. */
+               poptPrintUsage(pc, stderr, 0);
+               fprintf(stderr, "%s: %s\n",
+                               poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+                               poptStrerror(opt));
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       if (ns_opt == NULL) {
+               poptPrintUsage(pc, stderr, 0);
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       if (set_signal_handler()) {
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+
+       if (strncmp(ns_opt, "cgroup", 6) == 0) {
+               ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
+       } else if (strncmp(ns_opt, "ipc", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWIPC, "ipc");
+       } else if (strncmp(ns_opt, "mnt", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWNS, "mnt");
+       } else if (strncmp(ns_opt, "net", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWNET, "net");
+       } else if (strncmp(ns_opt, "pid", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWPID, "pid");
+       } else if (strncmp(ns_opt, "time", 4) == 0) {
+               ret = do_the_needful(CLONE_NEWTIME, "time");
+       } else if (strncmp(ns_opt, "user", 4) == 0) {
+               /*
+                * Will always fail, requires a single threaded application,
+                * which can't happen with UST.
+                */
+               ret = do_the_needful(CLONE_NEWUSER, "user");
+       } else if (strncmp(ns_opt, "uts", 3) == 0) {
+               ret = do_the_needful(CLONE_NEWUTS, "uts");
+       } else {
+               printf("invalid ns id\n");
+               ret = EXIT_FAILURE;
+               goto end;
+       }
+       ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
+end:
+       poptFreeContext(pc);
+       return ret;
+}
index f377de58b72458b262e8b3c511ae6fd84fbadec3..c05c665a1e0127a3616057e649f73cebb0bd5f34 100644 (file)
@@ -5,7 +5,10 @@ AM_CPPFLAGS += -I$(top_srcdir)/tests/utils -I$(srcdir) \
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-events
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-events
-gen_ust_events_SOURCES = gen-ust-events.c tp.c tp.h
+gen_ust_events_SOURCES = \
+       gen-ust-events.cpp \
+       tp.c \
+       tp.h
 gen_ust_events_LDADD = $(UST_LIBS) \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS)
 gen_ust_events_LDADD = $(UST_LIBS) \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS)
diff --git a/tests/utils/testapp/gen-ust-events/gen-ust-events.c b/tests/utils/testapp/gen-ust-events/gen-ust-events.c
deleted file mode 100644 (file)
index cf88199..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <getopt.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <signal.h>
-#include <poll.h>
-#include <errno.h>
-#include "utils.h"
-#include "signal-helper.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-static struct option long_options[] =
-{
-       /* These options set a flag. */
-       {"iter", required_argument, 0, 'i'},
-       {"wait", required_argument, 0, 'w'},
-       {"sync-after-first-event", required_argument, 0, 'a'},
-       {"sync-before-last-event", required_argument, 0, 'b'},
-       {"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}
-};
-
-int main(int argc, char **argv)
-{
-       unsigned int i, netint;
-       int option_index;
-       int option;
-       long values[] = { 1, 2, 3 };
-       char text[10] = "test";
-       char escape[10] = "\\*";
-       double dbl = 2.0;
-       float flt = 2222.0;
-       uint32_t net_values[] = { 1, 2, 3 };
-       int nr_iter = 100, ret = 0, first_event_file_created = 0;
-       useconds_t nr_usec = 0;
-       char *after_first_event_file_path = NULL;
-       char *before_last_event_file_path = NULL;
-       /*
-        * Touch a file to indicate that all events except one were
-        * generated.
-        */
-       char *before_last_event_file_path_touch = NULL;
-       /* Touch file when we are exiting */
-       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:e:f",
-                               long_options, &option_index)) != -1) {
-               switch (option) {
-               case 'a':
-                       after_first_event_file_path = strdup(optarg);
-                       break;
-               case 'b':
-                       before_last_event_file_path = strdup(optarg);
-                       break;
-               case 'c':
-                       before_last_event_file_path_touch = strdup(optarg);
-                       break;
-               case 'd':
-                       before_exit_file_path = strdup(optarg);
-                       break;
-               case 'e':
-                       before_exit_file_path_touch = strdup(optarg);
-                       break;
-               case 'f':
-                       emit_end_event = true;
-                       break;
-               case 'i':
-                       nr_iter = atoi(optarg);
-                       break;
-               case 'w':
-                       nr_usec = atoi(optarg);
-                       break;
-               case '?':
-                       /* getopt_long already printed an error message. */
-               default:
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       if (optind != argc) {
-               fprintf(stderr, "Error: takes long options only.\n");
-
-               /*
-                * Aborting the test program for now because callers typically don't check
-                * the test program return value, and the transition from positional
-                * arguments to getopt causes hangs when caller scripts are not updated.
-                * An abort is easier to diagnose and fix. This is a temporary solution:
-                * we should eventually ensure that all scripts test and report the test
-                * app return values.
-                */
-               abort();
-
-               ret = -1;
-               goto end;
-       }
-
-
-       if (set_signal_handler()) {
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
-               if (nr_iter >= 0 && i == nr_iter - 1) {
-                       if (before_last_event_file_path_touch) {
-                               ret = create_file(before_last_event_file_path_touch);
-                               if (ret != 0) {
-                                       goto end;
-                               }
-                       }
-
-                       /*
-                        * Wait on synchronization before writing last
-                        * event.
-                        */
-                       if (before_last_event_file_path) {
-                               ret = wait_on_file(before_last_event_file_path);
-                               if (ret != 0) {
-                                       goto end;
-                               }
-                       }
-               }
-               netint = htonl(i);
-               tracepoint(tp, tptest, i, netint, values, text,
-                       strlen(text), escape, net_values, dbl, flt);
-
-               /*
-                * First loop we create the file if asked to indicate
-                * that at least one tracepoint has been hit.
-                */
-               if (after_first_event_file_path && first_event_file_created == 0) {
-                       ret = create_file(after_first_event_file_path);
-
-                       if (ret != 0) {
-                               goto end;
-                       } else {
-                               first_event_file_created = 1;
-                       }
-               }
-
-               if (nr_usec) {
-                       if (usleep_safe(nr_usec)) {
-                               ret = -1;
-                               goto end;
-                       }
-               }
-               if (should_quit) {
-                       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) {
-                       goto end;
-               }
-       }
-       if (before_exit_file_path) {
-               ret = wait_on_file(before_exit_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-end:
-       free(after_first_event_file_path);
-       free(before_last_event_file_path);
-       free(before_last_event_file_path_touch);
-       free(before_exit_file_path);
-       free(before_exit_file_path_touch);
-       exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
-}
diff --git a/tests/utils/testapp/gen-ust-events/gen-ust-events.cpp b/tests/utils/testapp/gen-ust-events/gen-ust-events.cpp
new file mode 100644 (file)
index 0000000..cf88199
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <poll.h>
+#include <errno.h>
+#include "utils.h"
+#include "signal-helper.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+static struct option long_options[] =
+{
+       /* These options set a flag. */
+       {"iter", required_argument, 0, 'i'},
+       {"wait", required_argument, 0, 'w'},
+       {"sync-after-first-event", required_argument, 0, 'a'},
+       {"sync-before-last-event", required_argument, 0, 'b'},
+       {"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}
+};
+
+int main(int argc, char **argv)
+{
+       unsigned int i, netint;
+       int option_index;
+       int option;
+       long values[] = { 1, 2, 3 };
+       char text[10] = "test";
+       char escape[10] = "\\*";
+       double dbl = 2.0;
+       float flt = 2222.0;
+       uint32_t net_values[] = { 1, 2, 3 };
+       int nr_iter = 100, ret = 0, first_event_file_created = 0;
+       useconds_t nr_usec = 0;
+       char *after_first_event_file_path = NULL;
+       char *before_last_event_file_path = NULL;
+       /*
+        * Touch a file to indicate that all events except one were
+        * generated.
+        */
+       char *before_last_event_file_path_touch = NULL;
+       /* Touch file when we are exiting */
+       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:e:f",
+                               long_options, &option_index)) != -1) {
+               switch (option) {
+               case 'a':
+                       after_first_event_file_path = strdup(optarg);
+                       break;
+               case 'b':
+                       before_last_event_file_path = strdup(optarg);
+                       break;
+               case 'c':
+                       before_last_event_file_path_touch = strdup(optarg);
+                       break;
+               case 'd':
+                       before_exit_file_path = strdup(optarg);
+                       break;
+               case 'e':
+                       before_exit_file_path_touch = strdup(optarg);
+                       break;
+               case 'f':
+                       emit_end_event = true;
+                       break;
+               case 'i':
+                       nr_iter = atoi(optarg);
+                       break;
+               case 'w':
+                       nr_usec = atoi(optarg);
+                       break;
+               case '?':
+                       /* getopt_long already printed an error message. */
+               default:
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       if (optind != argc) {
+               fprintf(stderr, "Error: takes long options only.\n");
+
+               /*
+                * Aborting the test program for now because callers typically don't check
+                * the test program return value, and the transition from positional
+                * arguments to getopt causes hangs when caller scripts are not updated.
+                * An abort is easier to diagnose and fix. This is a temporary solution:
+                * we should eventually ensure that all scripts test and report the test
+                * app return values.
+                */
+               abort();
+
+               ret = -1;
+               goto end;
+       }
+
+
+       if (set_signal_handler()) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
+               if (nr_iter >= 0 && i == nr_iter - 1) {
+                       if (before_last_event_file_path_touch) {
+                               ret = create_file(before_last_event_file_path_touch);
+                               if (ret != 0) {
+                                       goto end;
+                               }
+                       }
+
+                       /*
+                        * Wait on synchronization before writing last
+                        * event.
+                        */
+                       if (before_last_event_file_path) {
+                               ret = wait_on_file(before_last_event_file_path);
+                               if (ret != 0) {
+                                       goto end;
+                               }
+                       }
+               }
+               netint = htonl(i);
+               tracepoint(tp, tptest, i, netint, values, text,
+                       strlen(text), escape, net_values, dbl, flt);
+
+               /*
+                * First loop we create the file if asked to indicate
+                * that at least one tracepoint has been hit.
+                */
+               if (after_first_event_file_path && first_event_file_created == 0) {
+                       ret = create_file(after_first_event_file_path);
+
+                       if (ret != 0) {
+                               goto end;
+                       } else {
+                               first_event_file_created = 1;
+                       }
+               }
+
+               if (nr_usec) {
+                       if (usleep_safe(nr_usec)) {
+                               ret = -1;
+                               goto end;
+                       }
+               }
+               if (should_quit) {
+                       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) {
+                       goto end;
+               }
+       }
+       if (before_exit_file_path) {
+               ret = wait_on_file(before_exit_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+end:
+       free(after_first_event_file_path);
+       free(before_last_event_file_path);
+       free(before_last_event_file_path_touch);
+       free(before_exit_file_path);
+       free(before_exit_file_path_touch);
+       exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
+}
index 7330f1fb95c70e807b8e9962f1e7b6ca44582aa2..955200c2b9c248c47ec9e18ec7f22d8f114418b0 100644 (file)
@@ -5,7 +5,10 @@ AM_CPPFLAGS += -I$(srcdir) -I$(top_srcdir)/tests/utils \
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-nevents-str
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-nevents-str
-gen_ust_nevents_str_SOURCES = gen-ust-nevents-str.c tp.c tp.h
+gen_ust_nevents_str_SOURCES = \
+       gen-ust-nevents-str.cpp \
+       tp.c \
+       tp.h
 gen_ust_nevents_str_LDADD = $(UST_LIBS) \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS)
 gen_ust_nevents_str_LDADD = $(UST_LIBS) \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS)
diff --git a/tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str.c b/tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str.c
deleted file mode 100644 (file)
index d68501b..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <stdio.h>
-#include "signal-helper.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-int main(int argc, char **argv)
-{
-       int count = 0, i = 0, arg_i = 0;
-
-       if (set_signal_handler()) {
-               return 1;
-       }
-
-       if (argc <= 3) {
-               fprintf(stderr, "Usage: %s COUNT STRING [STRING]...\n",
-                       argv[0]);
-               return 1;
-       }
-
-       if (argc >= 2) {
-               count = atoi(argv[1]);
-       }
-
-       if (count < 0) {
-               return 0;
-       }
-
-       for (i = 0, arg_i = 2; i < count; i++) {
-               tracepoint(tp, the_string, i, arg_i, argv[arg_i]);
-
-               arg_i++;
-               if (arg_i == argc) {
-                       arg_i = 2;
-               }
-               if (should_quit) {
-                       break;
-               }
-       }
-
-       return 0;
-}
diff --git a/tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str.cpp b/tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str.cpp
new file mode 100644 (file)
index 0000000..d68501b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <stdio.h>
+#include "signal-helper.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+int main(int argc, char **argv)
+{
+       int count = 0, i = 0, arg_i = 0;
+
+       if (set_signal_handler()) {
+               return 1;
+       }
+
+       if (argc <= 3) {
+               fprintf(stderr, "Usage: %s COUNT STRING [STRING]...\n",
+                       argv[0]);
+               return 1;
+       }
+
+       if (argc >= 2) {
+               count = atoi(argv[1]);
+       }
+
+       if (count < 0) {
+               return 0;
+       }
+
+       for (i = 0, arg_i = 2; i < count; i++) {
+               tracepoint(tp, the_string, i, arg_i, argv[arg_i]);
+
+               arg_i++;
+               if (arg_i == argc) {
+                       arg_i = 2;
+               }
+               if (should_quit) {
+                       break;
+               }
+       }
+
+       return 0;
+}
index 0ddbd9d390a489947969dcf0a78e81ce1c2bf224..cb869715dd47280f084de8a5a7f2699efe46e338 100644 (file)
@@ -5,7 +5,10 @@ AM_CPPFLAGS += -I$(srcdir) -I$(top_srcdir)/tests/utils \
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-nevents
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-nevents
-gen_ust_nevents_SOURCES = gen-ust-nevents.c tp.c tp.h
+gen_ust_nevents_SOURCES = \
+       gen-ust-nevents.cpp \
+       tp.c \
+       tp.h
 gen_ust_nevents_LDADD = $(UST_LIBS) \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS)
 gen_ust_nevents_LDADD = $(UST_LIBS) \
                $(top_builddir)/tests/utils/libtestutils.la \
                $(DL_LIBS)
diff --git a/tests/utils/testapp/gen-ust-nevents/gen-ust-nevents.c b/tests/utils/testapp/gen-ust-nevents/gen-ust-nevents.c
deleted file mode 100644 (file)
index ec71023..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <arpa/inet.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "utils.h"
-#include "signal-helper.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-static struct option long_options[] =
-{
-       /* These options set a flag. */
-       {"iter", required_argument, 0, 'i'},
-       {"wait", required_argument, 0, 'w'},
-       {"create-in-main", required_argument, 0, 'm'},
-       {"wait-before-first-event", required_argument, 0, 'b'},
-       {0, 0, 0, 0}
-};
-
-int main(int argc, char **argv)
-{
-       int i, netint, ret = 0, option_index, option;
-       long values[] = { 1, 2, 3 };
-       char text[10] = "test";
-       double dbl = 2.0;
-       float flt = 2222.0;
-       unsigned int nr_iter = 100;
-       useconds_t nr_usec = 0;
-       char *wait_before_first_event_file_path = NULL;
-       char *create_in_main_file_path = NULL;
-
-       while ((option = getopt_long(argc, argv, "i:w:b:m:",
-                       long_options, &option_index)) != -1) {
-               switch (option) {
-               case 'b':
-                       wait_before_first_event_file_path = strdup(optarg);
-                       break;
-               case 'm':
-                       create_in_main_file_path = strdup(optarg);
-                       break;
-               case 'i':
-                       nr_iter = atoi(optarg);
-                       break;
-               case 'w':
-                       nr_usec = atoi(optarg);
-                       break;
-               case '?':
-                       /* getopt_long already printed an error message. */
-               default:
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       if (set_signal_handler()) {
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * The two following sync points allow for tests to do work after the
-        * app has started BUT before it generates any events.
-        */
-       if (create_in_main_file_path) {
-               ret = create_file(create_in_main_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-
-       if (wait_before_first_event_file_path) {
-               ret = wait_on_file(wait_before_first_event_file_path);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < nr_iter; i++) {
-               netint = htonl(i);
-               tracepoint(tp, tptest1, i, netint, values, text, strlen(text),
-                          dbl, flt);
-               tracepoint(tp, tptest2, i, netint, values, text, strlen(text),
-                               dbl, flt);
-               tracepoint(tp, tptest3, i, netint, values, text, strlen(text),
-                               dbl, flt);
-               tracepoint(tp, tptest4, i, netint, values, text, strlen(text),
-                               dbl, flt);
-               tracepoint(tp, tptest5, i, netint, values, text, strlen(text),
-                               dbl, flt);
-               if (nr_usec) {
-                       if (usleep_safe(nr_usec)) {
-                               ret = -1;
-                               goto end;
-                       }
-               }
-               if (should_quit) {
-                       break;
-               }
-       }
-
-end:
-       free(create_in_main_file_path);
-       free(wait_before_first_event_file_path);
-       exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
-}
diff --git a/tests/utils/testapp/gen-ust-nevents/gen-ust-nevents.cpp b/tests/utils/testapp/gen-ust-nevents/gen-ust-nevents.cpp
new file mode 100644 (file)
index 0000000..ec71023
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "utils.h"
+#include "signal-helper.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+static struct option long_options[] =
+{
+       /* These options set a flag. */
+       {"iter", required_argument, 0, 'i'},
+       {"wait", required_argument, 0, 'w'},
+       {"create-in-main", required_argument, 0, 'm'},
+       {"wait-before-first-event", required_argument, 0, 'b'},
+       {0, 0, 0, 0}
+};
+
+int main(int argc, char **argv)
+{
+       int i, netint, ret = 0, option_index, option;
+       long values[] = { 1, 2, 3 };
+       char text[10] = "test";
+       double dbl = 2.0;
+       float flt = 2222.0;
+       unsigned int nr_iter = 100;
+       useconds_t nr_usec = 0;
+       char *wait_before_first_event_file_path = NULL;
+       char *create_in_main_file_path = NULL;
+
+       while ((option = getopt_long(argc, argv, "i:w:b:m:",
+                       long_options, &option_index)) != -1) {
+               switch (option) {
+               case 'b':
+                       wait_before_first_event_file_path = strdup(optarg);
+                       break;
+               case 'm':
+                       create_in_main_file_path = strdup(optarg);
+                       break;
+               case 'i':
+                       nr_iter = atoi(optarg);
+                       break;
+               case 'w':
+                       nr_usec = atoi(optarg);
+                       break;
+               case '?':
+                       /* getopt_long already printed an error message. */
+               default:
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       if (set_signal_handler()) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * The two following sync points allow for tests to do work after the
+        * app has started BUT before it generates any events.
+        */
+       if (create_in_main_file_path) {
+               ret = create_file(create_in_main_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+
+       if (wait_before_first_event_file_path) {
+               ret = wait_on_file(wait_before_first_event_file_path);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < nr_iter; i++) {
+               netint = htonl(i);
+               tracepoint(tp, tptest1, i, netint, values, text, strlen(text),
+                          dbl, flt);
+               tracepoint(tp, tptest2, i, netint, values, text, strlen(text),
+                               dbl, flt);
+               tracepoint(tp, tptest3, i, netint, values, text, strlen(text),
+                               dbl, flt);
+               tracepoint(tp, tptest4, i, netint, values, text, strlen(text),
+                               dbl, flt);
+               tracepoint(tp, tptest5, i, netint, values, text, strlen(text),
+                               dbl, flt);
+               if (nr_usec) {
+                       if (usleep_safe(nr_usec)) {
+                               ret = -1;
+                               goto end;
+                       }
+               }
+               if (should_quit) {
+                       break;
+               }
+       }
+
+end:
+       free(create_in_main_file_path);
+       free(wait_before_first_event_file_path);
+       exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
+}
index b16f6ce54576842ca888a5a40409986822d103ce..17678c6978754d6ad9c5f6e48e9dd770bf42ebce 100644 (file)
@@ -5,6 +5,6 @@ AM_CPPFLAGS += -I$(srcdir) \
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-tracef
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS = gen-ust-tracef
-gen_ust_tracef_SOURCES = gen-ust-tracef.c
+gen_ust_tracef_SOURCES = gen-ust-tracef.cpp
 gen_ust_tracef_LDADD = $(UST_LIBS) $(DL_LIBS)
 endif
 gen_ust_tracef_LDADD = $(UST_LIBS) $(DL_LIBS)
 endif
diff --git a/tests/utils/testapp/gen-ust-tracef/gen-ust-tracef.c b/tests/utils/testapp/gen-ust-tracef/gen-ust-tracef.c
deleted file mode 100644 (file)
index f0f6cc6..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/macros.h>
-#include <lttng/tracef.h>
-#include "signal-helper.h"
-
-const char *str = "test string";
-
-static
-void create_file(const char *path)
-{
-       int ret;
-
-       LTTNG_ASSERT(path);
-
-       ret = creat(path, S_IRWXU);
-       if (ret < 0) {
-               fprintf(stderr, "Failed to create file %s\n", path);
-               return;
-       }
-
-       (void) close(ret);
-}
-
-int main(int argc, char **argv)
-{
-       int i;
-       unsigned int nr_iter = 100;
-       useconds_t nr_usec = 0;
-       char *tmp_file_path = NULL;
-
-       if (set_signal_handler()) {
-               return 1;
-       }
-
-       if (argc >= 2) {
-               nr_iter = atoi(argv[1]);
-       }
-
-       if (argc >= 3) {
-               /* By default, don't wait unless user specifies. */
-               nr_usec = atoi(argv[2]);
-       }
-
-       if (argc >= 4) {
-               tmp_file_path = argv[3];
-       }
-
-       for (i = 0; i < nr_iter; i++) {
-               tracef("Test message %d with string \"%s\"", i, str);
-
-               /*
-                * First loop we create the file if asked to indicate
-                * that at least one tracepoint has been hit.
-                */
-               if (i == 0 && tmp_file_path) {
-                       create_file(tmp_file_path);
-               }
-               usleep(nr_usec);
-               if (should_quit) {
-                       break;
-               }
-       }
-
-       return 0;
-}
diff --git a/tests/utils/testapp/gen-ust-tracef/gen-ust-tracef.cpp b/tests/utils/testapp/gen-ust-tracef/gen-ust-tracef.cpp
new file mode 100644 (file)
index 0000000..f0f6cc6
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/macros.h>
+#include <lttng/tracef.h>
+#include "signal-helper.h"
+
+const char *str = "test string";
+
+static
+void create_file(const char *path)
+{
+       int ret;
+
+       LTTNG_ASSERT(path);
+
+       ret = creat(path, S_IRWXU);
+       if (ret < 0) {
+               fprintf(stderr, "Failed to create file %s\n", path);
+               return;
+       }
+
+       (void) close(ret);
+}
+
+int main(int argc, char **argv)
+{
+       int i;
+       unsigned int nr_iter = 100;
+       useconds_t nr_usec = 0;
+       char *tmp_file_path = NULL;
+
+       if (set_signal_handler()) {
+               return 1;
+       }
+
+       if (argc >= 2) {
+               nr_iter = atoi(argv[1]);
+       }
+
+       if (argc >= 3) {
+               /* By default, don't wait unless user specifies. */
+               nr_usec = atoi(argv[2]);
+       }
+
+       if (argc >= 4) {
+               tmp_file_path = argv[3];
+       }
+
+       for (i = 0; i < nr_iter; i++) {
+               tracef("Test message %d with string \"%s\"", i, str);
+
+               /*
+                * First loop we create the file if asked to indicate
+                * that at least one tracepoint has been hit.
+                */
+               if (i == 0 && tmp_file_path) {
+                       create_file(tmp_file_path);
+               }
+               usleep(nr_usec);
+               if (should_quit) {
+                       break;
+               }
+       }
+
+       return 0;
+}
index 8d2668f314c16d511e7b9434dc668f8f453c332b..ceadcb37277225bab6adf92667032888f6be49a0 100644 (file)
@@ -24,10 +24,9 @@ static
 int set_signal_handler(void)
 {
        int ret;
 int set_signal_handler(void)
 {
        int ret;
-       struct sigaction sa = {
-               .sa_flags = 0,
-               .sa_handler = sighandler,
-       };
+       struct sigaction sa {};
+       sa.sa_flags = 0;
+       sa.sa_handler = sighandler;
 
        ret = sigemptyset(&sa.sa_mask);
        if (ret) {
 
        ret = sigemptyset(&sa.sa_mask);
        if (ret) {
diff --git a/tests/utils/utils.c b/tests/utils/utils.c
deleted file mode 100644 (file)
index fee74e9..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <common/compat/time.h>
-#include <common/time.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-
-#include "utils.h"
-
-static inline
-int64_t elapsed_time_ns(struct timespec *t1, struct timespec *t2)
-{
-       struct timespec delta;
-
-       LTTNG_ASSERT(t1 && t2);
-       delta.tv_sec = t2->tv_sec - t1->tv_sec;
-       delta.tv_nsec = t2->tv_nsec - t1->tv_nsec;
-       return ((int64_t) NSEC_PER_SEC * (int64_t) delta.tv_sec) +
-                       (int64_t) delta.tv_nsec;
-}
-
-int usleep_safe(useconds_t usec)
-{
-       int ret = 0;
-       struct timespec t1, t2;
-       int64_t time_remaining_ns = (int64_t) usec * (int64_t) NSEC_PER_USEC;
-
-       ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t1);
-       if (ret) {
-               ret = -1;
-               perror("clock_gettime");
-               goto end;
-       }
-
-       while (time_remaining_ns > 0) {
-               ret = usleep(time_remaining_ns / (int64_t) NSEC_PER_USEC);
-               if (ret && errno != EINTR) {
-                       perror("usleep");
-                       goto end;
-               }
-
-               ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t2);
-               if (ret) {
-                       perror("clock_gettime");
-                       goto end;
-               }
-
-               time_remaining_ns -= elapsed_time_ns(&t1, &t2);
-       }
-end:
-       return ret;
-}
-
-int create_file(const char *path)
-{
-       int ret;
-
-       if (!path) {
-               return -1;
-       }
-
-       ret = creat(path, S_IRWXU);
-       if (ret < 0) {
-               perror("creat");
-               return -1;
-       }
-
-       ret = close(ret);
-       if (ret < 0) {
-               perror("close");
-               return -1;
-       }
-
-       return 0;
-}
-
-int wait_on_file(const char *path)
-{
-       int ret;
-       struct stat buf;
-
-       if (!path) {
-               return -1;
-       }
-
-       for (;;) {
-               ret = stat(path, &buf);
-               if (ret == -1 && errno == ENOENT) {
-                       ret = poll(NULL, 0, 10);        /* 10 ms delay */
-                       /* Should return 0 everytime */
-                       if (ret) {
-                               if (ret < 0) {
-                                       perror("perror");
-                               } else {
-                                       fprintf(stderr,
-                                               "poll return value is larger than zero\n");
-                               }
-                               return -1;
-                       }
-                       continue;                       /* retry */
-               }
-               if (ret) {
-                       perror("stat");
-                       return -1;
-               }
-               break;  /* found */
-       }
-
-       return 0;
-}
diff --git a/tests/utils/utils.cpp b/tests/utils/utils.cpp
new file mode 100644 (file)
index 0000000..fee74e9
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <common/compat/time.h>
+#include <common/time.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+
+#include "utils.h"
+
+static inline
+int64_t elapsed_time_ns(struct timespec *t1, struct timespec *t2)
+{
+       struct timespec delta;
+
+       LTTNG_ASSERT(t1 && t2);
+       delta.tv_sec = t2->tv_sec - t1->tv_sec;
+       delta.tv_nsec = t2->tv_nsec - t1->tv_nsec;
+       return ((int64_t) NSEC_PER_SEC * (int64_t) delta.tv_sec) +
+                       (int64_t) delta.tv_nsec;
+}
+
+int usleep_safe(useconds_t usec)
+{
+       int ret = 0;
+       struct timespec t1, t2;
+       int64_t time_remaining_ns = (int64_t) usec * (int64_t) NSEC_PER_USEC;
+
+       ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t1);
+       if (ret) {
+               ret = -1;
+               perror("clock_gettime");
+               goto end;
+       }
+
+       while (time_remaining_ns > 0) {
+               ret = usleep(time_remaining_ns / (int64_t) NSEC_PER_USEC);
+               if (ret && errno != EINTR) {
+                       perror("usleep");
+                       goto end;
+               }
+
+               ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t2);
+               if (ret) {
+                       perror("clock_gettime");
+                       goto end;
+               }
+
+               time_remaining_ns -= elapsed_time_ns(&t1, &t2);
+       }
+end:
+       return ret;
+}
+
+int create_file(const char *path)
+{
+       int ret;
+
+       if (!path) {
+               return -1;
+       }
+
+       ret = creat(path, S_IRWXU);
+       if (ret < 0) {
+               perror("creat");
+               return -1;
+       }
+
+       ret = close(ret);
+       if (ret < 0) {
+               perror("close");
+               return -1;
+       }
+
+       return 0;
+}
+
+int wait_on_file(const char *path)
+{
+       int ret;
+       struct stat buf;
+
+       if (!path) {
+               return -1;
+       }
+
+       for (;;) {
+               ret = stat(path, &buf);
+               if (ret == -1 && errno == ENOENT) {
+                       ret = poll(NULL, 0, 10);        /* 10 ms delay */
+                       /* Should return 0 everytime */
+                       if (ret) {
+                               if (ret < 0) {
+                                       perror("perror");
+                               } else {
+                                       fprintf(stderr,
+                                               "poll return value is larger than zero\n");
+                               }
+                               return -1;
+                       }
+                       continue;                       /* retry */
+               }
+               if (ret) {
+                       perror("stat");
+                       return -1;
+               }
+               break;  /* found */
+       }
+
+       return 0;
+}
index afacf8d2f8cda641976aca064a6b52cf6c456fcd..fc06b4ace4d7a058d481d1a8ecec519b07ae5bce 100644 (file)
@@ -8,6 +8,10 @@
 #ifndef TEST_UTILS_H
 #define TEST_UTILS_H
 
 #ifndef TEST_UTILS_H
 #define TEST_UTILS_H
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #if !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE))
 
 /*
 #if !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE))
 
 /*
@@ -37,4 +41,8 @@ int usleep_safe(useconds_t usec);
 int create_file(const char *path);
 int wait_on_file(const char *path);
 
 int create_file(const char *path);
 int wait_on_file(const char *path);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* TEST_UTILS_H */
 #endif /* TEST_UTILS_H */
index 7fac127281f1075438b6044857d6e2e68c89a598..7997d94e126369e694114d5b7584d593ba637c8b 100644 (file)
@@ -1,11 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 noinst_PROGRAMS = validate_xml extract_xml pretty_xml
 # SPDX-License-Identifier: GPL-2.0-only
 
 noinst_PROGRAMS = validate_xml extract_xml pretty_xml
-validate_xml_SOURCES = validate_xml.c
+validate_xml_SOURCES = validate_xml.cpp
 validate_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 validate_xml_LDADD = $(libxml2_LIBS)
 
 validate_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 validate_xml_LDADD = $(libxml2_LIBS)
 
-extract_xml_SOURCES = extract_xml.c
+extract_xml_SOURCES = extract_xml.cpp
 extract_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 extract_xml_LDADD = $(libxml2_LIBS)
 
 extract_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 extract_xml_LDADD = $(libxml2_LIBS)
 
diff --git a/tests/utils/xml-utils/extract_xml.c b/tests/utils/xml-utils/extract_xml.c
deleted file mode 100644 (file)
index 011f38f..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-/*
- * Usage: extract_xml [-v|-e] xml_path xpath_expression
- * Evaluate XPath expression and prints result node set.
- * args[1] path to the xml file
- * args[2] xpath expression to extract
- * If -e look if node exist return "true" else nothing
- * If -v is set the name of the node will appear with his value delimited by
- * a semicolon(;)
- * Ex:
- * Command:extract_xml ../file.xml /test/node/text()
- * Output:
- *     a
- *     b
- *     c
- * With -v
- *     node;a;
- *     node;b;
- *     node;c;
- */
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <libxml/tree.h>
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <common/defaults.h>
-
-#if defined(LIBXML_XPATH_ENABLED)
-
-static int opt_verbose;
-static int node_exist;
-static bool result = false;
-
-/**
- * print_xpath_nodes:
- * nodes:  the nodes set.
- * output: the output file handle.
- *
- * Print the node content to the file
- */
-static int print_xpath_nodes(xmlDocPtr doc, xmlNodeSetPtr nodes, FILE *output)
-{
-       int ret = 0;
-       int size;
-       int i;
-
-       xmlNodePtr cur;
-       xmlChar *node_child_value_string = NULL;
-
-       LTTNG_ASSERT(output);
-       size = (nodes) ? nodes->nodeNr : 0;
-
-       for (i = 0; i < size; ++i) {
-               LTTNG_ASSERT(nodes->nodeTab[i]);
-
-               if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
-                       fprintf(stderr, "ERR:%s\n",
-                                       "This executable does not support xml namespacing\n");
-                       ret = -1;
-                       goto end;
-               } else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
-                       cur = nodes->nodeTab[i];
-
-                       if (xmlChildElementCount(cur) == 0) {
-                               if (xmlNodeIsText(cur->children)) {
-                                       node_child_value_string = xmlNodeListGetString(doc,
-                                                       cur->children, 1);
-                                       if (node_exist) {
-                                               result = true;
-                                       } else if (opt_verbose) {
-                                               fprintf(output, "%s;%s;\n", cur->name,
-                                                               node_child_value_string);
-                                       } else {
-                                               fprintf(output, "%s\n",
-                                                               node_child_value_string);
-                                       }
-                                       xmlFree(node_child_value_string);
-                               } else {
-                                       /* We don't want to print non-final element */
-                                       if (node_exist) {
-                                               result = true;
-                                       } else {
-                                               fprintf(stderr, "ERR:%s\n",
-                                                               "Xpath expression return non-final xml element");
-                                               ret = -1;
-                                               goto end;
-                                       }
-                               }
-                       } else {
-                               if (node_exist) {
-                                       result = true;
-                               } else {
-                                       /* We don't want to print non-final element */
-                                       fprintf(stderr, "ERR:%s\n",
-                                                       "Xpath expression return non-final xml element");
-                                       ret = -1;
-                                       goto end;
-                               }
-                       }
-
-               } else {
-                       cur = nodes->nodeTab[i];
-                       if (node_exist) {
-                               result = true;
-                       } else if (opt_verbose) {
-                               fprintf(output, "%s;%s;\n", cur->parent->name, cur->content);
-                       } else {
-                               fprintf(output, "%s\n", cur->content);
-                       }
-               }
-       }
-       /* Command Success */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static int register_lttng_namespace(xmlXPathContextPtr xpathCtx)
-{
-       int ret;
-       xmlChar *prefix;
-       xmlChar *ns = NULL;
-
-       prefix = xmlCharStrdup("lttng");
-       if (!prefix) {
-               ret = -1;
-               goto end;
-       }
-
-       ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE);
-       if (!ns) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = xmlXPathRegisterNs(xpathCtx, prefix, ns);
-end:
-       xmlFree(prefix);
-       xmlFree(ns);
-       return ret;
-}
-
-/*
- * Extract element corresponding to xpath
- * xml_path     The path to the xml file
- * xpath:       The xpath to evaluate.
- *
- * Evaluate an xpath expression onto an xml file.
- * and print the result one by line.
- *
- * Returns 0 on success and a negative value otherwise.
- */
-static int extract_xpath(const char *xml_path, const xmlChar *xpath)
-{
-       int ret;
-       xmlDocPtr doc = NULL;
-       xmlXPathContextPtr xpathCtx = NULL;
-       xmlXPathObjectPtr xpathObj = NULL;
-
-       LTTNG_ASSERT(xml_path);
-       LTTNG_ASSERT(xpath);
-
-       /* Parse the xml file */
-       doc = xmlParseFile(xml_path);
-       if (!doc) {
-               fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
-               return -1;
-       }
-
-       /* Initialize a xpath context */
-       xpathCtx = xmlXPathNewContext(doc);
-       if (!xpathCtx) {
-               fprintf(stderr, "ERR: XPath context invalid\n");
-               xmlFreeDoc(doc);
-               return -1;
-       }
-
-       /* Register the LTTng MI namespace */
-       ret = register_lttng_namespace(xpathCtx);
-       if (ret) {
-               fprintf(stderr, "ERR: Could not register lttng namespace\n");
-               xmlXPathFreeContext(xpathCtx);
-               xmlFreeDoc(doc);
-               return -1;
-       }
-
-       /* Evaluate xpath expression */
-       xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
-       if (!xpathObj) {
-               fprintf(stderr, "ERR: invalid xpath expression \"%s\"\n", xpath);
-               xmlXPathFreeContext(xpathCtx);
-               xmlFreeDoc(doc);
-               return -1;
-       }
-
-       /* Print results */
-       if (print_xpath_nodes(doc, xpathObj->nodesetval, stdout)) {
-               xmlXPathFreeObject(xpathObj);
-               xmlXPathFreeContext(xpathCtx);
-               xmlFreeDoc(doc);
-               return -1;
-       }
-       if (node_exist && result) {
-               fprintf(stdout, "true\n");
-       }
-
-       /* Cleanup */
-       xmlXPathFreeObject(xpathObj);
-       xmlXPathFreeContext(xpathCtx);
-       xmlFreeDoc(doc);
-
-       return 0;
-}
-
-int main(int argc, char **argv)
-{
-       int opt;
-
-       /* Parse command line and process file */
-       while ((opt = getopt(argc, argv, "ve")) != -1) {
-               switch (opt) {
-               case 'v':
-                       opt_verbose = 1;
-                       break;
-               case 'e':
-                       node_exist = 1;
-                       break;
-               default:
-                       abort();
-               }
-       }
-
-       if (!(optind + 1 < argc)) {
-               fprintf(stderr, "ERR:%s\n", "Arguments missing");
-               return -1;
-       }
-
-       /* Init libxml */
-       xmlInitParser();
-       xmlKeepBlanksDefault(0);
-       if (access(argv[optind], F_OK)) {
-               fprintf(stderr, "ERR:%s\n", "Xml path not valid");
-               return -1;
-       }
-       /* Do the main job */
-       if (extract_xpath(argv[optind], (xmlChar *)argv[optind+1])) {
-               return -1;
-       }
-
-       /* Shutdown libxml */
-       xmlCleanupParser();
-
-       return 0;
-}
-
-#else
-int main(void)
-{
-       fprintf(stderr, "XPath support not compiled in\n");
-       return -1;
-}
-#endif
diff --git a/tests/utils/xml-utils/extract_xml.cpp b/tests/utils/xml-utils/extract_xml.cpp
new file mode 100644 (file)
index 0000000..011f38f
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+/*
+ * Usage: extract_xml [-v|-e] xml_path xpath_expression
+ * Evaluate XPath expression and prints result node set.
+ * args[1] path to the xml file
+ * args[2] xpath expression to extract
+ * If -e look if node exist return "true" else nothing
+ * If -v is set the name of the node will appear with his value delimited by
+ * a semicolon(;)
+ * Ex:
+ * Command:extract_xml ../file.xml /test/node/text()
+ * Output:
+ *     a
+ *     b
+ *     c
+ * With -v
+ *     node;a;
+ *     node;b;
+ *     node;c;
+ */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <common/defaults.h>
+
+#if defined(LIBXML_XPATH_ENABLED)
+
+static int opt_verbose;
+static int node_exist;
+static bool result = false;
+
+/**
+ * print_xpath_nodes:
+ * nodes:  the nodes set.
+ * output: the output file handle.
+ *
+ * Print the node content to the file
+ */
+static int print_xpath_nodes(xmlDocPtr doc, xmlNodeSetPtr nodes, FILE *output)
+{
+       int ret = 0;
+       int size;
+       int i;
+
+       xmlNodePtr cur;
+       xmlChar *node_child_value_string = NULL;
+
+       LTTNG_ASSERT(output);
+       size = (nodes) ? nodes->nodeNr : 0;
+
+       for (i = 0; i < size; ++i) {
+               LTTNG_ASSERT(nodes->nodeTab[i]);
+
+               if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
+                       fprintf(stderr, "ERR:%s\n",
+                                       "This executable does not support xml namespacing\n");
+                       ret = -1;
+                       goto end;
+               } else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
+                       cur = nodes->nodeTab[i];
+
+                       if (xmlChildElementCount(cur) == 0) {
+                               if (xmlNodeIsText(cur->children)) {
+                                       node_child_value_string = xmlNodeListGetString(doc,
+                                                       cur->children, 1);
+                                       if (node_exist) {
+                                               result = true;
+                                       } else if (opt_verbose) {
+                                               fprintf(output, "%s;%s;\n", cur->name,
+                                                               node_child_value_string);
+                                       } else {
+                                               fprintf(output, "%s\n",
+                                                               node_child_value_string);
+                                       }
+                                       xmlFree(node_child_value_string);
+                               } else {
+                                       /* We don't want to print non-final element */
+                                       if (node_exist) {
+                                               result = true;
+                                       } else {
+                                               fprintf(stderr, "ERR:%s\n",
+                                                               "Xpath expression return non-final xml element");
+                                               ret = -1;
+                                               goto end;
+                                       }
+                               }
+                       } else {
+                               if (node_exist) {
+                                       result = true;
+                               } else {
+                                       /* We don't want to print non-final element */
+                                       fprintf(stderr, "ERR:%s\n",
+                                                       "Xpath expression return non-final xml element");
+                                       ret = -1;
+                                       goto end;
+                               }
+                       }
+
+               } else {
+                       cur = nodes->nodeTab[i];
+                       if (node_exist) {
+                               result = true;
+                       } else if (opt_verbose) {
+                               fprintf(output, "%s;%s;\n", cur->parent->name, cur->content);
+                       } else {
+                               fprintf(output, "%s\n", cur->content);
+                       }
+               }
+       }
+       /* Command Success */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static int register_lttng_namespace(xmlXPathContextPtr xpathCtx)
+{
+       int ret;
+       xmlChar *prefix;
+       xmlChar *ns = NULL;
+
+       prefix = xmlCharStrdup("lttng");
+       if (!prefix) {
+               ret = -1;
+               goto end;
+       }
+
+       ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE);
+       if (!ns) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = xmlXPathRegisterNs(xpathCtx, prefix, ns);
+end:
+       xmlFree(prefix);
+       xmlFree(ns);
+       return ret;
+}
+
+/*
+ * Extract element corresponding to xpath
+ * xml_path     The path to the xml file
+ * xpath:       The xpath to evaluate.
+ *
+ * Evaluate an xpath expression onto an xml file.
+ * and print the result one by line.
+ *
+ * Returns 0 on success and a negative value otherwise.
+ */
+static int extract_xpath(const char *xml_path, const xmlChar *xpath)
+{
+       int ret;
+       xmlDocPtr doc = NULL;
+       xmlXPathContextPtr xpathCtx = NULL;
+       xmlXPathObjectPtr xpathObj = NULL;
+
+       LTTNG_ASSERT(xml_path);
+       LTTNG_ASSERT(xpath);
+
+       /* Parse the xml file */
+       doc = xmlParseFile(xml_path);
+       if (!doc) {
+               fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
+               return -1;
+       }
+
+       /* Initialize a xpath context */
+       xpathCtx = xmlXPathNewContext(doc);
+       if (!xpathCtx) {
+               fprintf(stderr, "ERR: XPath context invalid\n");
+               xmlFreeDoc(doc);
+               return -1;
+       }
+
+       /* Register the LTTng MI namespace */
+       ret = register_lttng_namespace(xpathCtx);
+       if (ret) {
+               fprintf(stderr, "ERR: Could not register lttng namespace\n");
+               xmlXPathFreeContext(xpathCtx);
+               xmlFreeDoc(doc);
+               return -1;
+       }
+
+       /* Evaluate xpath expression */
+       xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
+       if (!xpathObj) {
+               fprintf(stderr, "ERR: invalid xpath expression \"%s\"\n", xpath);
+               xmlXPathFreeContext(xpathCtx);
+               xmlFreeDoc(doc);
+               return -1;
+       }
+
+       /* Print results */
+       if (print_xpath_nodes(doc, xpathObj->nodesetval, stdout)) {
+               xmlXPathFreeObject(xpathObj);
+               xmlXPathFreeContext(xpathCtx);
+               xmlFreeDoc(doc);
+               return -1;
+       }
+       if (node_exist && result) {
+               fprintf(stdout, "true\n");
+       }
+
+       /* Cleanup */
+       xmlXPathFreeObject(xpathObj);
+       xmlXPathFreeContext(xpathCtx);
+       xmlFreeDoc(doc);
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int opt;
+
+       /* Parse command line and process file */
+       while ((opt = getopt(argc, argv, "ve")) != -1) {
+               switch (opt) {
+               case 'v':
+                       opt_verbose = 1;
+                       break;
+               case 'e':
+                       node_exist = 1;
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       if (!(optind + 1 < argc)) {
+               fprintf(stderr, "ERR:%s\n", "Arguments missing");
+               return -1;
+       }
+
+       /* Init libxml */
+       xmlInitParser();
+       xmlKeepBlanksDefault(0);
+       if (access(argv[optind], F_OK)) {
+               fprintf(stderr, "ERR:%s\n", "Xml path not valid");
+               return -1;
+       }
+       /* Do the main job */
+       if (extract_xpath(argv[optind], (xmlChar *)argv[optind+1])) {
+               return -1;
+       }
+
+       /* Shutdown libxml */
+       xmlCleanupParser();
+
+       return 0;
+}
+
+#else
+int main(void)
+{
+       fprintf(stderr, "XPath support not compiled in\n");
+       return -1;
+}
+#endif
diff --git a/tests/utils/xml-utils/validate_xml.c b/tests/utils/xml-utils/validate_xml.c
deleted file mode 100644 (file)
index bb67e56..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
- /*
-  * This script validate and xml from an xsd.
-  * argv[1] Path of the xsd
-  * argv[2] Path to the XML to be validated
-  */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <libxml/xmlschemas.h>
-#include <libxml/parser.h>
-
-#include <lttng/lttng-error.h>
-#include <common/macros.h>
-
-struct validation_ctx {
-       xmlSchemaParserCtxtPtr parser_ctx;
-       xmlSchemaPtr schema;
-       xmlSchemaValidCtxtPtr schema_validation_ctx;
-};
-
-enum command_err_code {
-       CMD_SUCCESS = 0,
-       CMD_ERROR
-};
-
-static
-void xml_error_handler(void *ctx, const char *format, ...)
-{
-       char *err_msg;
-       va_list args;
-       int ret;
-
-       va_start(args, format);
-       ret = vasprintf(&err_msg, format, args);
-       va_end(args);
-       if (ret == -1) {
-               fprintf(stderr, "ERR: %s\n",
-                               "String allocation failed in xml error handle");
-               return;
-       }
-
-       fprintf(stderr, "XML Error: %s\n", err_msg);
-       free(err_msg);
-}
-
-static
-void fini_validation_ctx(
-       struct validation_ctx *ctx)
-{
-       if (ctx->parser_ctx) {
-               xmlSchemaFreeParserCtxt(ctx->parser_ctx);
-       }
-
-       if (ctx->schema) {
-               xmlSchemaFree(ctx->schema);
-       }
-
-       if (ctx->schema_validation_ctx) {
-               xmlSchemaFreeValidCtxt(ctx->schema_validation_ctx);
-       }
-
-       memset(ctx, 0, sizeof(struct validation_ctx));
-}
-
-static
-int init_validation_ctx(
-       struct validation_ctx *ctx, char *xsd_path)
-{
-       int ret;
-
-       if (!xsd_path) {
-               ret = -LTTNG_ERR_NOMEM;
-               goto end;
-       }
-
-       ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path);
-       if (!ctx->parser_ctx) {
-               ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-               goto end;
-       }
-       xmlSchemaSetParserErrors(ctx->parser_ctx, xml_error_handler,
-               xml_error_handler, NULL);
-
-       ctx->schema = xmlSchemaParse(ctx->parser_ctx);
-       if (!ctx->schema) {
-               ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-               goto end;
-       }
-
-       ctx->schema_validation_ctx = xmlSchemaNewValidCtxt(ctx->schema);
-       if (!ctx->schema_validation_ctx) {
-               ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
-               goto end;
-       }
-
-       xmlSchemaSetValidErrors(ctx->schema_validation_ctx, xml_error_handler,
-                       xml_error_handler, NULL);
-       ret = 0;
-
-end:
-       if (ret) {
-               fini_validation_ctx(ctx);
-       }
-       return ret;
-}
-
-static int validate_xml(const char *xml_file_path, struct validation_ctx *ctx)
-{
-       int ret;
-       xmlDocPtr doc = NULL;
-
-       LTTNG_ASSERT(xml_file_path);
-       LTTNG_ASSERT(ctx);
-
-       /* Open the document */
-       doc = xmlParseFile(xml_file_path);
-       if (!doc) {
-               ret = LTTNG_ERR_MI_IO_FAIL;
-               goto end;
-       }
-
-       /* Validate against the validation ctx (xsd) */
-       ret = xmlSchemaValidateDoc(ctx->schema_validation_ctx, doc);
-       if (ret) {
-               fprintf(stderr, "ERR: %s\n", "XML is not valid againt provided XSD");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       ret = CMD_SUCCESS;
-end:
-       return ret;
-
-
-}
-int main(int argc, char **argv, char *env[])
-{
-       int ret;
-       struct validation_ctx ctx = { 0 };
-
-       /* Check if we have all argument */
-       if (argc < 3) {
-               fprintf(stderr, "ERR: %s\n", "Missing arguments");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Check if xsd file exist */
-       ret = access(argv[1], F_OK);
-       if (ret < 0) {
-               fprintf(stderr, "ERR: %s\n", "Xsd path not valid");
-               goto end;
-       }
-
-       /* Check if xml to validate exist */
-       ret = access(argv[2], F_OK);
-       if (ret < 0) {
-               fprintf(stderr, "ERR: %s\n", "XML path not valid");
-               goto end;
-       }
-
-       /* initialize the validation ctx */
-       ret = init_validation_ctx(&ctx, argv[1]);
-       if (ret) {
-               goto end;
-       }
-
-       ret = validate_xml(argv[2], &ctx);
-
-       fini_validation_ctx(&ctx);
-
-end:
-       return ret;
-}
diff --git a/tests/utils/xml-utils/validate_xml.cpp b/tests/utils/xml-utils/validate_xml.cpp
new file mode 100644 (file)
index 0000000..bb67e56
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+ /*
+  * This script validate and xml from an xsd.
+  * argv[1] Path of the xsd
+  * argv[2] Path to the XML to be validated
+  */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <libxml/xmlschemas.h>
+#include <libxml/parser.h>
+
+#include <lttng/lttng-error.h>
+#include <common/macros.h>
+
+struct validation_ctx {
+       xmlSchemaParserCtxtPtr parser_ctx;
+       xmlSchemaPtr schema;
+       xmlSchemaValidCtxtPtr schema_validation_ctx;
+};
+
+enum command_err_code {
+       CMD_SUCCESS = 0,
+       CMD_ERROR
+};
+
+static
+void xml_error_handler(void *ctx, const char *format, ...)
+{
+       char *err_msg;
+       va_list args;
+       int ret;
+
+       va_start(args, format);
+       ret = vasprintf(&err_msg, format, args);
+       va_end(args);
+       if (ret == -1) {
+               fprintf(stderr, "ERR: %s\n",
+                               "String allocation failed in xml error handle");
+               return;
+       }
+
+       fprintf(stderr, "XML Error: %s\n", err_msg);
+       free(err_msg);
+}
+
+static
+void fini_validation_ctx(
+       struct validation_ctx *ctx)
+{
+       if (ctx->parser_ctx) {
+               xmlSchemaFreeParserCtxt(ctx->parser_ctx);
+       }
+
+       if (ctx->schema) {
+               xmlSchemaFree(ctx->schema);
+       }
+
+       if (ctx->schema_validation_ctx) {
+               xmlSchemaFreeValidCtxt(ctx->schema_validation_ctx);
+       }
+
+       memset(ctx, 0, sizeof(struct validation_ctx));
+}
+
+static
+int init_validation_ctx(
+       struct validation_ctx *ctx, char *xsd_path)
+{
+       int ret;
+
+       if (!xsd_path) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path);
+       if (!ctx->parser_ctx) {
+               ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+               goto end;
+       }
+       xmlSchemaSetParserErrors(ctx->parser_ctx, xml_error_handler,
+               xml_error_handler, NULL);
+
+       ctx->schema = xmlSchemaParse(ctx->parser_ctx);
+       if (!ctx->schema) {
+               ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+               goto end;
+       }
+
+       ctx->schema_validation_ctx = xmlSchemaNewValidCtxt(ctx->schema);
+       if (!ctx->schema_validation_ctx) {
+               ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+               goto end;
+       }
+
+       xmlSchemaSetValidErrors(ctx->schema_validation_ctx, xml_error_handler,
+                       xml_error_handler, NULL);
+       ret = 0;
+
+end:
+       if (ret) {
+               fini_validation_ctx(ctx);
+       }
+       return ret;
+}
+
+static int validate_xml(const char *xml_file_path, struct validation_ctx *ctx)
+{
+       int ret;
+       xmlDocPtr doc = NULL;
+
+       LTTNG_ASSERT(xml_file_path);
+       LTTNG_ASSERT(ctx);
+
+       /* Open the document */
+       doc = xmlParseFile(xml_file_path);
+       if (!doc) {
+               ret = LTTNG_ERR_MI_IO_FAIL;
+               goto end;
+       }
+
+       /* Validate against the validation ctx (xsd) */
+       ret = xmlSchemaValidateDoc(ctx->schema_validation_ctx, doc);
+       if (ret) {
+               fprintf(stderr, "ERR: %s\n", "XML is not valid againt provided XSD");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       ret = CMD_SUCCESS;
+end:
+       return ret;
+
+
+}
+int main(int argc, char **argv, char *env[])
+{
+       int ret;
+       struct validation_ctx ctx = { 0 };
+
+       /* Check if we have all argument */
+       if (argc < 3) {
+               fprintf(stderr, "ERR: %s\n", "Missing arguments");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Check if xsd file exist */
+       ret = access(argv[1], F_OK);
+       if (ret < 0) {
+               fprintf(stderr, "ERR: %s\n", "Xsd path not valid");
+               goto end;
+       }
+
+       /* Check if xml to validate exist */
+       ret = access(argv[2], F_OK);
+       if (ret < 0) {
+               fprintf(stderr, "ERR: %s\n", "XML path not valid");
+               goto end;
+       }
+
+       /* initialize the validation ctx */
+       ret = init_validation_ctx(&ctx, argv[1]);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_xml(argv[2], &ctx);
+
+       fini_validation_ctx(&ctx);
+
+end:
+       return ret;
+}
This page took 0.215613 seconds and 4 git commands to generate.